Merge remote-tracking branch 'upstream/master' into edge-3.3
This commit is contained in:
		
						commit
						08f11b0d1b
					
				@ -32,12 +32,13 @@ import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
import org.thingsboard.server.common.data.EntityType;
 | 
			
		||||
import org.thingsboard.server.common.data.OtaPackage;
 | 
			
		||||
import org.thingsboard.server.common.data.OtaPackageInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
 | 
			
		||||
import org.thingsboard.server.common.data.audit.ActionType;
 | 
			
		||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
 | 
			
		||||
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
 | 
			
		||||
import org.thingsboard.server.common.data.ota.OtaPackageType;
 | 
			
		||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.OtaPackageId;
 | 
			
		||||
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
 | 
			
		||||
import org.thingsboard.server.common.data.ota.OtaPackageType;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageData;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageLink;
 | 
			
		||||
import org.thingsboard.server.queue.util.TbCoreComponent;
 | 
			
		||||
@ -109,12 +110,12 @@ public class OtaPackageController extends BaseController {
 | 
			
		||||
    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
 | 
			
		||||
    @RequestMapping(value = "/otaPackage", method = RequestMethod.POST)
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public OtaPackageInfo saveOtaPackageInfo(@RequestBody OtaPackageInfo otaPackageInfo) throws ThingsboardException {
 | 
			
		||||
    public OtaPackageInfo saveOtaPackageInfo(@RequestBody SaveOtaPackageInfoRequest otaPackageInfo) throws ThingsboardException {
 | 
			
		||||
        boolean created = otaPackageInfo.getId() == null;
 | 
			
		||||
        try {
 | 
			
		||||
            otaPackageInfo.setTenantId(getTenantId());
 | 
			
		||||
            checkEntity(otaPackageInfo.getId(), otaPackageInfo, Resource.OTA_PACKAGE);
 | 
			
		||||
            OtaPackageInfo savedOtaPackageInfo = otaPackageService.saveOtaPackageInfo(otaPackageInfo);
 | 
			
		||||
            OtaPackageInfo savedOtaPackageInfo = otaPackageService.saveOtaPackageInfo(new OtaPackageInfo(otaPackageInfo), otaPackageInfo.isUsesUrl());
 | 
			
		||||
            logEntityAction(savedOtaPackageInfo.getId(), savedOtaPackageInfo,
 | 
			
		||||
                    null, created ? ActionType.ADDED : ActionType.UPDATED, null);
 | 
			
		||||
            return savedOtaPackageInfo;
 | 
			
		||||
 | 
			
		||||
@ -274,14 +274,18 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onSuccess(@Nullable Void tmp) {
 | 
			
		||||
                log.trace("[{}] Success save telemetry with target firmware for device!", deviceId);
 | 
			
		||||
                updateAttributes(device, otaPackage, ts, tenantId, deviceId, otaPackageType);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Throwable t) {
 | 
			
		||||
                log.error("[{}] Failed to save telemetry with target firmware for device!", deviceId, t);
 | 
			
		||||
                updateAttributes(device, otaPackage, ts, tenantId, deviceId, otaPackageType);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateAttributes(Device device, OtaPackageInfo otaPackage, long ts, TenantId tenantId, DeviceId deviceId, OtaPackageType otaPackageType) {
 | 
			
		||||
        List<AttributeKvEntry> attributes = new ArrayList<>();
 | 
			
		||||
        attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, TITLE), otaPackage.getTitle())));
 | 
			
		||||
        attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, VERSION), otaPackage.getVersion())));
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,7 @@ import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.server.common.data.DeviceProfile;
 | 
			
		||||
import org.thingsboard.server.common.data.OtaPackage;
 | 
			
		||||
import org.thingsboard.server.common.data.OtaPackageInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
 | 
			
		||||
import org.thingsboard.server.common.data.Tenant;
 | 
			
		||||
import org.thingsboard.server.common.data.User;
 | 
			
		||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
 | 
			
		||||
@ -92,11 +93,12 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveFirmware() throws Exception {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUsesUrl(false);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
 | 
			
		||||
 | 
			
		||||
@ -109,7 +111,7 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
 | 
			
		||||
        savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode());
 | 
			
		||||
 | 
			
		||||
        save(savedFirmwareInfo);
 | 
			
		||||
        save(new SaveOtaPackageInfoRequest(savedFirmwareInfo, false));
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo foundFirmwareInfo = doGet("/api/otaPackage/info/" + savedFirmwareInfo.getId().getId().toString(), OtaPackageInfo.class);
 | 
			
		||||
        Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle());
 | 
			
		||||
@ -117,11 +119,12 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveFirmwareData() throws Exception {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUsesUrl(false);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
 | 
			
		||||
 | 
			
		||||
@ -134,7 +137,7 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
 | 
			
		||||
        savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode());
 | 
			
		||||
 | 
			
		||||
        save(savedFirmwareInfo);
 | 
			
		||||
        save(new SaveOtaPackageInfoRequest(savedFirmwareInfo, false));
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo foundFirmwareInfo = doGet("/api/otaPackage/info/" + savedFirmwareInfo.getId().getId().toString(), OtaPackageInfo.class);
 | 
			
		||||
        Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle());
 | 
			
		||||
@ -151,26 +154,31 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateFirmwareFromDifferentTenant() throws Exception {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUsesUrl(false);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
 | 
			
		||||
 | 
			
		||||
        loginDifferentTenant();
 | 
			
		||||
        doPost("/api/otaPackage", savedFirmwareInfo, OtaPackageInfo.class, status().isForbidden());
 | 
			
		||||
        doPost("/api/otaPackage",
 | 
			
		||||
                new SaveOtaPackageInfoRequest(savedFirmwareInfo, false),
 | 
			
		||||
                OtaPackageInfo.class,
 | 
			
		||||
                status().isForbidden());
 | 
			
		||||
        deleteDifferentTenant();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindFirmwareInfoById() throws Exception {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUsesUrl(false);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
 | 
			
		||||
 | 
			
		||||
@ -181,11 +189,12 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindFirmwareById() throws Exception {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUsesUrl(false);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
 | 
			
		||||
 | 
			
		||||
@ -201,11 +210,12 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteFirmware() throws Exception {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUsesUrl(false);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
 | 
			
		||||
 | 
			
		||||
@ -220,11 +230,12 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
    public void testFindTenantFirmwares() throws Exception {
 | 
			
		||||
        List<OtaPackageInfo> otaPackages = new ArrayList<>();
 | 
			
		||||
        for (int i = 0; i < 165; i++) {
 | 
			
		||||
            OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
            SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
 | 
			
		||||
            firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
            firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
            firmwareInfo.setTitle(TITLE);
 | 
			
		||||
            firmwareInfo.setVersion(VERSION + i);
 | 
			
		||||
            firmwareInfo.setUsesUrl(false);
 | 
			
		||||
 | 
			
		||||
            OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
 | 
			
		||||
 | 
			
		||||
@ -263,11 +274,12 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
        List<OtaPackageInfo> allOtaPackages = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < 165; i++) {
 | 
			
		||||
            OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
            SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
 | 
			
		||||
            firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
            firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
            firmwareInfo.setTitle(TITLE);
 | 
			
		||||
            firmwareInfo.setVersion(VERSION + i);
 | 
			
		||||
            firmwareInfo.setUsesUrl(false);
 | 
			
		||||
 | 
			
		||||
            OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
 | 
			
		||||
 | 
			
		||||
@ -316,8 +328,7 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
 | 
			
		||||
        Assert.assertEquals(allOtaPackages, allLoadedOtaPackages);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private OtaPackageInfo save(OtaPackageInfo firmwareInfo) throws Exception {
 | 
			
		||||
    private OtaPackageInfo save(SaveOtaPackageInfoRequest firmwareInfo) throws Exception {
 | 
			
		||||
        return doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -372,38 +372,44 @@ public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest {
 | 
			
		||||
                                                    LwM2MClientCredentials credentials,
 | 
			
		||||
                                                    NetworkConfig coapConfig,
 | 
			
		||||
                                                    String endpoint) throws Exception {
 | 
			
		||||
        createDeviceProfile(TRANSPORT_CONFIGURATION);
 | 
			
		||||
        Device device = createDevice(credentials);
 | 
			
		||||
        LwM2MTestClient client = null;
 | 
			
		||||
        try {
 | 
			
		||||
            createDeviceProfile(TRANSPORT_CONFIGURATION);
 | 
			
		||||
            Device device = createDevice(credentials);
 | 
			
		||||
 | 
			
		||||
        SingleEntityFilter sef = new SingleEntityFilter();
 | 
			
		||||
        sef.setSingleEntity(device.getId());
 | 
			
		||||
        LatestValueCmd latestCmd = new LatestValueCmd();
 | 
			
		||||
        latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel")));
 | 
			
		||||
        EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null),
 | 
			
		||||
                Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
 | 
			
		||||
            SingleEntityFilter sef = new SingleEntityFilter();
 | 
			
		||||
            sef.setSingleEntity(device.getId());
 | 
			
		||||
            LatestValueCmd latestCmd = new LatestValueCmd();
 | 
			
		||||
            latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel")));
 | 
			
		||||
            EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null),
 | 
			
		||||
                    Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
 | 
			
		||||
 | 
			
		||||
        EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null);
 | 
			
		||||
        TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
 | 
			
		||||
        wrapper.setEntityDataCmds(Collections.singletonList(cmd));
 | 
			
		||||
            EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null);
 | 
			
		||||
            TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
 | 
			
		||||
            wrapper.setEntityDataCmds(Collections.singletonList(cmd));
 | 
			
		||||
 | 
			
		||||
        wsClient.send(mapper.writeValueAsString(wrapper));
 | 
			
		||||
        wsClient.waitForReply();
 | 
			
		||||
            wsClient.send(mapper.writeValueAsString(wrapper));
 | 
			
		||||
            wsClient.waitForReply();
 | 
			
		||||
 | 
			
		||||
        wsClient.registerWaitForUpdate();
 | 
			
		||||
        LwM2MTestClient client = new LwM2MTestClient(executor, endpoint);
 | 
			
		||||
            wsClient.registerWaitForUpdate();
 | 
			
		||||
            client = new LwM2MTestClient(executor, endpoint);
 | 
			
		||||
 | 
			
		||||
        client.init(security, coapConfig);
 | 
			
		||||
        String msg = wsClient.waitForUpdate();
 | 
			
		||||
            client.init(security, coapConfig);
 | 
			
		||||
            String msg = wsClient.waitForUpdate();
 | 
			
		||||
 | 
			
		||||
        EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
 | 
			
		||||
        Assert.assertEquals(1, update.getCmdId());
 | 
			
		||||
        List<EntityData> eData = update.getUpdate();
 | 
			
		||||
        Assert.assertNotNull(eData);
 | 
			
		||||
        Assert.assertEquals(1, eData.size());
 | 
			
		||||
        Assert.assertEquals(device.getId(), eData.get(0).getEntityId());
 | 
			
		||||
        Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES));
 | 
			
		||||
        var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel");
 | 
			
		||||
        Assert.assertEquals(42, Long.parseLong(tsValue.getValue()));
 | 
			
		||||
        client.destroy();
 | 
			
		||||
            EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
 | 
			
		||||
            Assert.assertEquals(1, update.getCmdId());
 | 
			
		||||
            List<EntityData> eData = update.getUpdate();
 | 
			
		||||
            Assert.assertNotNull(eData);
 | 
			
		||||
            Assert.assertEquals(1, eData.size());
 | 
			
		||||
            Assert.assertEquals(device.getId(), eData.get(0).getEntityId());
 | 
			
		||||
            Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES));
 | 
			
		||||
            var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel");
 | 
			
		||||
            Assert.assertEquals(42, Long.parseLong(tsValue.getValue()));
 | 
			
		||||
        } finally {
 | 
			
		||||
            if(client != null) {
 | 
			
		||||
                client.destroy();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,31 +19,24 @@ import com.fasterxml.jackson.core.type.TypeReference;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.thingsboard.server.common.data.Device;
 | 
			
		||||
import org.thingsboard.server.common.data.OtaPackageInfo;
 | 
			
		||||
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.common.data.query.EntityData;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityDataPageLink;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityDataQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityKey;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityKeyType;
 | 
			
		||||
import org.thingsboard.server.common.data.query.SingleEntityFilter;
 | 
			
		||||
import org.thingsboard.server.service.telemetry.cmd.TelemetryPluginCmdsWrapper;
 | 
			
		||||
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd;
 | 
			
		||||
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate;
 | 
			
		||||
import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd;
 | 
			
		||||
import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import static org.thingsboard.rest.client.utils.RestJsonConverter.toTimeseries;
 | 
			
		||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED;
 | 
			
		||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING;
 | 
			
		||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;
 | 
			
		||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.INITIATED;
 | 
			
		||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.QUEUED;
 | 
			
		||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED;
 | 
			
		||||
@ -138,116 +131,102 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFirmwareUpdateWithClientWithoutFirmwareInfo() throws Exception {
 | 
			
		||||
        createDeviceProfile(TRANSPORT_CONFIGURATION);
 | 
			
		||||
        NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
 | 
			
		||||
        clientCredentials.setEndpoint(ENDPOINT);
 | 
			
		||||
        Device device = createDevice(clientCredentials);
 | 
			
		||||
        LwM2MTestClient client = null;
 | 
			
		||||
        try {
 | 
			
		||||
            createDeviceProfile(TRANSPORT_CONFIGURATION);
 | 
			
		||||
            NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
 | 
			
		||||
            clientCredentials.setEndpoint(ENDPOINT);
 | 
			
		||||
            Device device = createDevice(clientCredentials);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo firmware = createFirmware();
 | 
			
		||||
            client = new LwM2MTestClient(executor, ENDPOINT);
 | 
			
		||||
            client.init(SECURITY, COAP_CONFIG);
 | 
			
		||||
 | 
			
		||||
        LwM2MTestClient client = new LwM2MTestClient(executor, ENDPOINT);
 | 
			
		||||
        client.init(SECURITY, COAP_CONFIG);
 | 
			
		||||
            Thread.sleep(1000);
 | 
			
		||||
 | 
			
		||||
        Thread.sleep(1000);
 | 
			
		||||
            device.setFirmwareId(createFirmware().getId());
 | 
			
		||||
            device = doPost("/api/device", device, Device.class);
 | 
			
		||||
 | 
			
		||||
        device.setFirmwareId(firmware.getId());
 | 
			
		||||
            Thread.sleep(5000);
 | 
			
		||||
 | 
			
		||||
        device = doPost("/api/device", device, Device.class);
 | 
			
		||||
            List<TsKvEntry> ts = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getId().getId() + "/values/timeseries?keys=fw_state", new TypeReference<>() {
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        Thread.sleep(1000);
 | 
			
		||||
            List<OtaPackageUpdateStatus> statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        SingleEntityFilter sef = new SingleEntityFilter();
 | 
			
		||||
        sef.setSingleEntity(device.getId());
 | 
			
		||||
        LatestValueCmd latestCmd = new LatestValueCmd();
 | 
			
		||||
        latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "fw_state")));
 | 
			
		||||
        EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null),
 | 
			
		||||
                Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
 | 
			
		||||
            List<OtaPackageUpdateStatus> expectedStatuses = Collections.singletonList(FAILED);
 | 
			
		||||
 | 
			
		||||
        EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null);
 | 
			
		||||
        TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
 | 
			
		||||
        wrapper.setEntityDataCmds(Collections.singletonList(cmd));
 | 
			
		||||
 | 
			
		||||
        wsClient.send(mapper.writeValueAsString(wrapper));
 | 
			
		||||
        wsClient.waitForReply();
 | 
			
		||||
 | 
			
		||||
        wsClient.registerWaitForUpdate();
 | 
			
		||||
 | 
			
		||||
        String msg = wsClient.waitForUpdate();
 | 
			
		||||
 | 
			
		||||
        EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
 | 
			
		||||
        Assert.assertEquals(1, update.getCmdId());
 | 
			
		||||
        List<EntityData> eData = update.getUpdate();
 | 
			
		||||
        Assert.assertNotNull(eData);
 | 
			
		||||
        Assert.assertEquals(1, eData.size());
 | 
			
		||||
        Assert.assertEquals(device.getId(), eData.get(0).getEntityId());
 | 
			
		||||
        Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES));
 | 
			
		||||
        var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("fw_state");
 | 
			
		||||
        Assert.assertEquals("FAILED", tsValue.getValue());
 | 
			
		||||
        client.destroy();
 | 
			
		||||
            Assert.assertEquals(expectedStatuses, statuses);
 | 
			
		||||
        } finally {
 | 
			
		||||
            if(client != null) {
 | 
			
		||||
                client.destroy();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFirmwareUpdateByObject5() throws Exception {
 | 
			
		||||
        createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
 | 
			
		||||
        NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
 | 
			
		||||
        clientCredentials.setEndpoint("OTA_" + ENDPOINT);
 | 
			
		||||
        Device device = createDevice(clientCredentials);
 | 
			
		||||
        LwM2MTestClient client = null;
 | 
			
		||||
        try {
 | 
			
		||||
            createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
 | 
			
		||||
            NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
 | 
			
		||||
            clientCredentials.setEndpoint("OTA_" + ENDPOINT);
 | 
			
		||||
            Device device = createDevice(clientCredentials);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo firmware = createFirmware();
 | 
			
		||||
            device.setFirmwareId(createFirmware().getId());
 | 
			
		||||
            device = doPost("/api/device", device, Device.class);
 | 
			
		||||
            Thread.sleep(1000);
 | 
			
		||||
 | 
			
		||||
        LwM2MTestClient client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT);
 | 
			
		||||
        client.init(SECURITY, COAP_CONFIG);
 | 
			
		||||
            client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT);
 | 
			
		||||
            client.init(SECURITY, COAP_CONFIG);
 | 
			
		||||
 | 
			
		||||
        Thread.sleep(1000);
 | 
			
		||||
            Thread.sleep(3000);
 | 
			
		||||
 | 
			
		||||
        device.setFirmwareId(firmware.getId());
 | 
			
		||||
            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<>() {
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        device = doPost("/api/device", device, Device.class);
 | 
			
		||||
            List<OtaPackageUpdateStatus> statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        Thread.sleep(4000);
 | 
			
		||||
            List<OtaPackageUpdateStatus> expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED);
 | 
			
		||||
 | 
			
		||||
        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().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        List<OtaPackageUpdateStatus> expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED);
 | 
			
		||||
 | 
			
		||||
        Assert.assertEquals(expectedStatuses, statuses);
 | 
			
		||||
 | 
			
		||||
        client.destroy();
 | 
			
		||||
            Assert.assertEquals(expectedStatuses, statuses);
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (client != null) {
 | 
			
		||||
                client.destroy();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSoftwareUpdateByObject9() throws Exception {
 | 
			
		||||
        createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
 | 
			
		||||
        NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
 | 
			
		||||
        clientCredentials.setEndpoint("OTA_" + ENDPOINT);
 | 
			
		||||
        Device device = createDevice(clientCredentials);
 | 
			
		||||
        LwM2MTestClient client = null;
 | 
			
		||||
        try {
 | 
			
		||||
            createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
 | 
			
		||||
            NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
 | 
			
		||||
            clientCredentials.setEndpoint("OTA_" + ENDPOINT);
 | 
			
		||||
            Device device = createDevice(clientCredentials);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo software = createSoftware();
 | 
			
		||||
            device.setSoftwareId(createSoftware().getId());
 | 
			
		||||
            device = doPost("/api/device", device, Device.class);
 | 
			
		||||
 | 
			
		||||
        LwM2MTestClient client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT);
 | 
			
		||||
        client.init(SECURITY, COAP_CONFIG);
 | 
			
		||||
            Thread.sleep(1000);
 | 
			
		||||
 | 
			
		||||
        Thread.sleep(1000);
 | 
			
		||||
            client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT);
 | 
			
		||||
            client.init(SECURITY, COAP_CONFIG);
 | 
			
		||||
 | 
			
		||||
        device.setSoftwareId(software.getId());
 | 
			
		||||
            Thread.sleep(3000);
 | 
			
		||||
 | 
			
		||||
        device = doPost("/api/device", device, Device.class);
 | 
			
		||||
            List<TsKvEntry> ts = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getId().getId() + "/values/timeseries?orderBy=ASC&keys=sw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() {
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        Thread.sleep(4000);
 | 
			
		||||
            List<OtaPackageUpdateStatus> statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        List<TsKvEntry> ts = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getId().getId() + "/values/timeseries?orderBy=ASC&keys=sw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() {
 | 
			
		||||
        }));
 | 
			
		||||
            List<OtaPackageUpdateStatus> expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED);
 | 
			
		||||
 | 
			
		||||
        List<OtaPackageUpdateStatus> statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        List<OtaPackageUpdateStatus> expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED);
 | 
			
		||||
 | 
			
		||||
        Assert.assertEquals(expectedStatuses, statuses);
 | 
			
		||||
 | 
			
		||||
        client.destroy();
 | 
			
		||||
            Assert.assertEquals(expectedStatuses, statuses);
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (client != null) {
 | 
			
		||||
                client.destroy();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -128,10 +128,14 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
 | 
			
		||||
 | 
			
		||||
    private void startDownloading() {
 | 
			
		||||
        scheduler.schedule(() -> {
 | 
			
		||||
            state.set(1);
 | 
			
		||||
            fireResourcesChange(3);
 | 
			
		||||
            state.set(2);
 | 
			
		||||
            fireResourcesChange(3);
 | 
			
		||||
            try {
 | 
			
		||||
                state.set(1);
 | 
			
		||||
                fireResourcesChange(3);
 | 
			
		||||
                Thread.sleep(100);
 | 
			
		||||
                state.set(2);
 | 
			
		||||
                fireResourcesChange(3);
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
            }
 | 
			
		||||
        }, 100, TimeUnit.MILLISECONDS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -144,7 +148,6 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
 | 
			
		||||
                updateResult.set(1);
 | 
			
		||||
                fireResourcesChange(5);
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }, 100, TimeUnit.MILLISECONDS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -18,11 +18,11 @@ package org.thingsboard.server.dao.ota;
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import org.thingsboard.server.common.data.OtaPackage;
 | 
			
		||||
import org.thingsboard.server.common.data.OtaPackageInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
 | 
			
		||||
import org.thingsboard.server.common.data.ota.OtaPackageType;
 | 
			
		||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.OtaPackageId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
 | 
			
		||||
import org.thingsboard.server.common.data.ota.OtaPackageType;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageData;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageLink;
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ import java.nio.ByteBuffer;
 | 
			
		||||
 | 
			
		||||
public interface OtaPackageService {
 | 
			
		||||
 | 
			
		||||
    OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo);
 | 
			
		||||
    OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo, boolean isUrl);
 | 
			
		||||
 | 
			
		||||
    OtaPackage saveOtaPackage(OtaPackage otaPackage);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,37 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.common.data;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
public class SaveOtaPackageInfoRequest extends OtaPackageInfo{
 | 
			
		||||
    boolean usesUrl;
 | 
			
		||||
 | 
			
		||||
    public SaveOtaPackageInfoRequest(OtaPackageInfo otaPackageInfo, boolean usesUrl) {
 | 
			
		||||
        super(otaPackageInfo);
 | 
			
		||||
        this.usesUrl = usesUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SaveOtaPackageInfoRequest(SaveOtaPackageInfoRequest saveOtaPackageInfoRequest) {
 | 
			
		||||
        super(saveOtaPackageInfoRequest);
 | 
			
		||||
        this.usesUrl = saveOtaPackageInfoRequest.isUsesUrl();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -77,8 +77,11 @@ public class BaseOtaPackageService implements OtaPackageService {
 | 
			
		||||
    private TbTenantProfileCache tenantProfileCache;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo) {
 | 
			
		||||
    public OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo, boolean isUrl) {
 | 
			
		||||
        log.trace("Executing saveOtaPackageInfo [{}]", otaPackageInfo);
 | 
			
		||||
        if(isUrl && (StringUtils.isEmpty(otaPackageInfo.getUrl()) || otaPackageInfo.getUrl().trim().length() == 0)) {
 | 
			
		||||
            throw new DataValidationException("Ota package URL should be specified!");
 | 
			
		||||
        }
 | 
			
		||||
        otaPackageInfoValidator.validate(otaPackageInfo, OtaPackageInfo::getTenantId);
 | 
			
		||||
        try {
 | 
			
		||||
            OtaPackageId otaPackageId = otaPackageInfo.getId();
 | 
			
		||||
@ -277,7 +280,9 @@ public class BaseOtaPackageService implements OtaPackageService {
 | 
			
		||||
                    throw new DataValidationException("Wrong otaPackage file!");
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                //TODO: validate url
 | 
			
		||||
                if(otaPackage.getData() != null) {
 | 
			
		||||
                    throw new DataValidationException("File can't be saved if URL present!");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -336,6 +341,10 @@ public class BaseOtaPackageService implements OtaPackageService {
 | 
			
		||||
        if (otaPackageOld.getDataSize() != null && !otaPackageOld.getDataSize().equals(otaPackage.getDataSize())) {
 | 
			
		||||
            throw new DataValidationException("Updating otaPackage data size is prohibited!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(otaPackageOld.getUrl() != null && !otaPackageOld.getUrl().equals(otaPackage.getUrl())) {
 | 
			
		||||
            throw new DataValidationException("Updating otaPackage URL is prohibited!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateImpl(OtaPackageInfo otaPackageInfo) {
 | 
			
		||||
@ -366,6 +375,15 @@ public class BaseOtaPackageService implements OtaPackageService {
 | 
			
		||||
        if (StringUtils.isEmpty(otaPackageInfo.getVersion())) {
 | 
			
		||||
            throw new DataValidationException("OtaPackage version should be specified!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(otaPackageInfo.getTitle().length() > 255) {
 | 
			
		||||
            throw new DataValidationException("The length of title should be equal or shorter than 255");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(otaPackageInfo.getVersion().length() > 255) {
 | 
			
		||||
            throw new DataValidationException("The length of version should be equal or shorter than 255");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private PaginatedRemover<TenantId, OtaPackageInfo> tenantOtaPackageRemover =
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
package org.thingsboard.server.dao.service;
 | 
			
		||||
 | 
			
		||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
 | 
			
		||||
import org.apache.commons.lang3.RandomStringUtils;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
@ -163,7 +164,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        firmware.setVersion(VERSION);
 | 
			
		||||
        firmware.setUrl(URL);
 | 
			
		||||
        firmware.setDataSize(0L);
 | 
			
		||||
        OtaPackageInfo savedFirmware = otaPackageService.saveOtaPackageInfo(firmware);
 | 
			
		||||
        OtaPackageInfo savedFirmware = otaPackageService.saveOtaPackageInfo(firmware, true);
 | 
			
		||||
 | 
			
		||||
        Assert.assertNotNull(savedFirmware);
 | 
			
		||||
        Assert.assertNotNull(savedFirmware.getId());
 | 
			
		||||
@ -174,7 +175,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        Assert.assertEquals(firmware.getContentType(), savedFirmware.getContentType());
 | 
			
		||||
 | 
			
		||||
        savedFirmware.setAdditionalInfo(JacksonUtil.newObjectNode());
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(savedFirmware);
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(savedFirmware, true);
 | 
			
		||||
 | 
			
		||||
        OtaPackage foundFirmware = otaPackageService.findOtaPackageById(tenantId, savedFirmware.getId());
 | 
			
		||||
        Assert.assertEquals(foundFirmware.getTitle(), savedFirmware.getTitle());
 | 
			
		||||
@ -190,7 +191,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = otaPackageService.saveOtaPackageInfo(firmwareInfo);
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = otaPackageService.saveOtaPackageInfo(firmwareInfo, false);
 | 
			
		||||
 | 
			
		||||
        Assert.assertNotNull(savedFirmwareInfo);
 | 
			
		||||
        Assert.assertNotNull(savedFirmwareInfo.getId());
 | 
			
		||||
@ -216,7 +217,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
 | 
			
		||||
        savedFirmwareInfo = otaPackageService.findOtaPackageInfoById(tenantId, savedFirmwareInfo.getId());
 | 
			
		||||
        savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode());
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(savedFirmwareInfo);
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(savedFirmwareInfo, false);
 | 
			
		||||
 | 
			
		||||
        OtaPackage foundFirmware = otaPackageService.findOtaPackageById(tenantId, firmware.getId());
 | 
			
		||||
        firmware.setAdditionalInfo(JacksonUtil.newObjectNode());
 | 
			
		||||
@ -399,7 +400,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(firmwareInfo);
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(firmwareInfo, false);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo newFirmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        newFirmwareInfo.setTenantId(tenantId);
 | 
			
		||||
@ -410,7 +411,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
 | 
			
		||||
        thrown.expect(DataValidationException.class);
 | 
			
		||||
        thrown.expectMessage("OtaPackage with such title and version already exists!");
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(newFirmwareInfo);
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(newFirmwareInfo, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@ -506,7 +507,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        firmware.setType(FIRMWARE);
 | 
			
		||||
        firmware.setTitle(TITLE);
 | 
			
		||||
        firmware.setVersion(VERSION);
 | 
			
		||||
        OtaPackageInfo savedFirmware = otaPackageService.saveOtaPackageInfo(firmware);
 | 
			
		||||
        OtaPackageInfo savedFirmware = otaPackageService.saveOtaPackageInfo(firmware, false);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo foundFirmware = otaPackageService.findOtaPackageInfoById(tenantId, savedFirmware.getId());
 | 
			
		||||
        Assert.assertNotNull(foundFirmware);
 | 
			
		||||
@ -543,7 +544,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        firmwareWithUrl.setUrl(URL);
 | 
			
		||||
        firmwareWithUrl.setDataSize(0L);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFwWithUrl = otaPackageService.saveOtaPackageInfo(firmwareWithUrl);
 | 
			
		||||
        OtaPackageInfo savedFwWithUrl = otaPackageService.saveOtaPackageInfo(firmwareWithUrl, true);
 | 
			
		||||
        savedFwWithUrl.setHasData(true);
 | 
			
		||||
 | 
			
		||||
        firmwares.add(savedFwWithUrl);
 | 
			
		||||
@ -588,7 +589,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        firmwareWithUrl.setUrl(URL);
 | 
			
		||||
        firmwareWithUrl.setDataSize(0L);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFwWithUrl = otaPackageService.saveOtaPackageInfo(firmwareWithUrl);
 | 
			
		||||
        OtaPackageInfo savedFwWithUrl = otaPackageService.saveOtaPackageInfo(firmwareWithUrl, true);
 | 
			
		||||
        savedFwWithUrl.setHasData(true);
 | 
			
		||||
 | 
			
		||||
        firmwares.add(savedFwWithUrl);
 | 
			
		||||
@ -627,6 +628,71 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        Assert.assertTrue(pageData.getData().isEmpty());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveOtaPackageInfoWithBlankAndEmptyUrl() {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUrl("   ");
 | 
			
		||||
        thrown.expect(DataValidationException.class);
 | 
			
		||||
        thrown.expectMessage("Ota package URL should be specified!");
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(firmwareInfo, true);
 | 
			
		||||
        firmwareInfo.setUrl("");
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(firmwareInfo, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveOtaPackageUrlCantBeUpdated() {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUrl(URL);
 | 
			
		||||
        firmwareInfo.setTenantId(tenantId);
 | 
			
		||||
 | 
			
		||||
        OtaPackageInfo savedFirmwareInfo = otaPackageService.saveOtaPackageInfo(firmwareInfo, true);
 | 
			
		||||
 | 
			
		||||
        thrown.expect(DataValidationException.class);
 | 
			
		||||
        thrown.expectMessage("Updating otaPackage URL is prohibited!");
 | 
			
		||||
 | 
			
		||||
        savedFirmwareInfo.setUrl("https://newurl.com");
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(savedFirmwareInfo, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveOtaPackageCantViolateSizeOfTitle() {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setTitle(RandomStringUtils.random(257));
 | 
			
		||||
        firmwareInfo.setVersion(VERSION);
 | 
			
		||||
        firmwareInfo.setUrl(URL);
 | 
			
		||||
        firmwareInfo.setTenantId(tenantId);
 | 
			
		||||
 | 
			
		||||
        thrown.expect(DataValidationException.class);
 | 
			
		||||
        thrown.expectMessage("The length of title should be equal or shorter than 255");
 | 
			
		||||
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(firmwareInfo, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveOtaPackageCantViolateSizeOfVersion() {
 | 
			
		||||
        OtaPackageInfo firmwareInfo = new OtaPackageInfo();
 | 
			
		||||
        firmwareInfo.setDeviceProfileId(deviceProfileId);
 | 
			
		||||
        firmwareInfo.setType(FIRMWARE);
 | 
			
		||||
        firmwareInfo.setUrl(URL);
 | 
			
		||||
        firmwareInfo.setTenantId(tenantId);
 | 
			
		||||
        firmwareInfo.setTitle(TITLE);
 | 
			
		||||
 | 
			
		||||
        firmwareInfo.setVersion(RandomStringUtils.random(257));
 | 
			
		||||
        thrown.expectMessage("The length of version should be equal or shorter than 255");
 | 
			
		||||
 | 
			
		||||
        otaPackageService.saveOtaPackageInfo(firmwareInfo, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private OtaPackage createFirmware(TenantId tenantId, String version) {
 | 
			
		||||
        OtaPackage firmware = new OtaPackage();
 | 
			
		||||
        firmware.setTenantId(tenantId);
 | 
			
		||||
@ -642,5 +708,4 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
 | 
			
		||||
        firmware.setDataSize(DATA_SIZE);
 | 
			
		||||
        return otaPackageService.saveOtaPackage(firmware);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2977,8 +2977,10 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
 | 
			
		||||
        ).getBody();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo) {
 | 
			
		||||
        return restTemplate.postForEntity(baseURL + "/api/otaPackage", otaPackageInfo, OtaPackageInfo.class).getBody();
 | 
			
		||||
    public OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo, boolean isUrl) {
 | 
			
		||||
        Map<String, String> params = new HashMap<>();
 | 
			
		||||
        params.put("isUrl", Boolean.toString(isUrl));
 | 
			
		||||
        return restTemplate.postForEntity(baseURL + "/api/otaPackage?isUrl={isUrl}", otaPackageInfo, OtaPackageInfo.class, params).getBody();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public OtaPackageInfo saveOtaPackageData(OtaPackageId otaPackageId, String checkSum, ChecksumAlgorithm checksumAlgorithm, MultipartFile file) throws Exception {
 | 
			
		||||
 | 
			
		||||
@ -93,17 +93,17 @@
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
      <section *ngIf="isAdd">
 | 
			
		||||
        <div class="mat-caption" style="margin: -8px 0 8px;" translate>ota-update.warning-after-save-no-edit</div>
 | 
			
		||||
        <mat-radio-group formControlName="resource" fxLayoutGap="16px">
 | 
			
		||||
          <mat-radio-button value="file">Upload binary file</mat-radio-button>
 | 
			
		||||
          <mat-radio-button value="url">Use external URL</mat-radio-button>
 | 
			
		||||
        <mat-radio-group formControlName="isURL" fxLayoutGap="16px">
 | 
			
		||||
          <mat-radio-button [value]="false">Upload binary file</mat-radio-button>
 | 
			
		||||
          <mat-radio-button [value]="true">Use external URL</mat-radio-button>
 | 
			
		||||
        </mat-radio-group>
 | 
			
		||||
      </section>
 | 
			
		||||
      <section *ngIf="entityForm.get('resource').value === 'file'">
 | 
			
		||||
      <section *ngIf="!entityForm.get('isURL').value">
 | 
			
		||||
        <section *ngIf="isAdd">
 | 
			
		||||
          <tb-file-input
 | 
			
		||||
            formControlName="file"
 | 
			
		||||
            workFromFileObj="true"
 | 
			
		||||
            [required]="entityForm.get('resource').value === 'file'"
 | 
			
		||||
            [required]="!entityForm.get('isURL').value"
 | 
			
		||||
            dropLabel="{{'ota-update.drop-file' | translate}}">
 | 
			
		||||
          </tb-file-input>
 | 
			
		||||
          <mat-checkbox formControlName="generateChecksum" style="margin-top: 16px">
 | 
			
		||||
@ -143,12 +143,12 @@
 | 
			
		||||
          </div>
 | 
			
		||||
        </section>
 | 
			
		||||
      </section>
 | 
			
		||||
      <section *ngIf="entityForm.get('resource').value === 'url'" style="margin-top: 8px">
 | 
			
		||||
      <section *ngIf="entityForm.get('isURL').value" style="margin-top: 8px">
 | 
			
		||||
        <mat-form-field class="mat-block">
 | 
			
		||||
          <mat-label translate>ota-update.direct-url</mat-label>
 | 
			
		||||
          <input matInput formControlName="url"
 | 
			
		||||
                 type="text"
 | 
			
		||||
                 [required]="entityForm.get('resource').value === 'url'">
 | 
			
		||||
                 [required]="entityForm.get('isURL').value">
 | 
			
		||||
          <mat-error *ngIf="entityForm.get('url').hasError('required') || entityForm.get('url').hasError('pattern')" translate>
 | 
			
		||||
            ota-update.direct-url-required
 | 
			
		||||
          </mat-error>
 | 
			
		||||
 | 
			
		||||
@ -56,11 +56,11 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    super.ngOnInit();
 | 
			
		||||
    this.entityForm.get('resource').valueChanges.pipe(
 | 
			
		||||
    this.entityForm.get('isURL').valueChanges.pipe(
 | 
			
		||||
      filter(() => this.isAdd),
 | 
			
		||||
      takeUntil(this.destroy$)
 | 
			
		||||
    ).subscribe((resource) => {
 | 
			
		||||
      if (resource === 'file') {
 | 
			
		||||
    ).subscribe((isURL) => {
 | 
			
		||||
      if (isURL === false) {
 | 
			
		||||
        this.entityForm.get('url').clearValidators();
 | 
			
		||||
        this.entityForm.get('file').setValidators(Validators.required);
 | 
			
		||||
        this.entityForm.get('url').updateValueAndValidity({emitEvent: false});
 | 
			
		||||
@ -97,7 +97,7 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O
 | 
			
		||||
      checksumAlgorithm: [entity && entity.checksumAlgorithm ? entity.checksumAlgorithm : ChecksumAlgorithm.SHA256],
 | 
			
		||||
      checksum: [entity ? entity.checksum : '', Validators.maxLength(1020)],
 | 
			
		||||
      url: [entity ? entity.url : ''],
 | 
			
		||||
      resource: ['file'],
 | 
			
		||||
      isURL: [false],
 | 
			
		||||
      additionalInfo: this.fb.group(
 | 
			
		||||
        {
 | 
			
		||||
          description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''],
 | 
			
		||||
@ -127,7 +127,7 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O
 | 
			
		||||
      dataSize: entity.dataSize,
 | 
			
		||||
      contentType: entity.contentType,
 | 
			
		||||
      url: entity.url,
 | 
			
		||||
      resource: isNotEmptyStr(entity.url) ? 'url' : 'file',
 | 
			
		||||
      isURL: isNotEmptyStr(entity.url),
 | 
			
		||||
      additionalInfo: {
 | 
			
		||||
        description: entity.additionalInfo ? entity.additionalInfo.description : ''
 | 
			
		||||
      }
 | 
			
		||||
@ -172,12 +172,11 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  prepareFormValue(formValue: any): any {
 | 
			
		||||
    if (formValue.resource === 'url') {
 | 
			
		||||
    if (formValue.isURL) {
 | 
			
		||||
      delete formValue.file;
 | 
			
		||||
    } else {
 | 
			
		||||
      delete formValue.url;
 | 
			
		||||
    }
 | 
			
		||||
    delete formValue.resource;
 | 
			
		||||
    delete formValue.generateChecksum;
 | 
			
		||||
    return super.prepareFormValue(formValue);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -99,6 +99,7 @@ export interface OtaPackageInfo extends BaseData<OtaPackageId> {
 | 
			
		||||
  contentType: string;
 | 
			
		||||
  dataSize?: number;
 | 
			
		||||
  additionalInfo?: any;
 | 
			
		||||
  isURL?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface OtaPackage extends OtaPackageInfo {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user