From d4784b30960d59475cef7fe18eaf15f37946c4f0 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 26 Jan 2022 12:11:52 +0200 Subject: [PATCH 1/5] Prohibit deletion of device profiles that are referenced by OTA packages --- .../org/thingsboard/server/dao/ota/OtaPackageService.java | 3 +++ .../server/dao/device/DeviceProfileServiceImpl.java | 3 +++ .../thingsboard/server/dao/ota/BaseOtaPackageService.java | 5 +++++ .../java/org/thingsboard/server/dao/ota/OtaPackageDao.java | 5 ++++- .../thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java | 7 +++++++ .../server/dao/sql/ota/OtaPackageRepository.java | 4 +++- .../server/dao/service/BaseOtaPackageServiceTest.java | 4 +++- 7 files changed, 28 insertions(+), 3 deletions(-) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java index b14653b1d0..638851f05d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java @@ -51,4 +51,7 @@ public interface OtaPackageService { void deleteOtaPackagesByTenantId(TenantId tenantId); long sumDataSizeByTenantId(TenantId tenantId); + + boolean existsByDeviceProfileId(DeviceProfileId deviceProfileId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 18a8a1ecde..c80834bfb6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -218,6 +218,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D if (deviceProfile != null && deviceProfile.isDefault()) { throw new DataValidationException("Deletion of Default Device Profile is prohibited!"); } + if (otaPackageService.existsByDeviceProfileId(deviceProfileId)) { + throw new DataValidationException("The device profile is referenced by OTA update package"); + } this.removeDeviceProfile(tenantId, deviceProfile); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java index 205b2c447b..c879fe6fdd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java @@ -223,6 +223,11 @@ public class BaseOtaPackageService implements OtaPackageService { return otaPackageDao.sumDataSizeByTenantId(tenantId); } + @Override + public boolean existsByDeviceProfileId(DeviceProfileId deviceProfileId) { + return otaPackageDao.existsByDeviceProfileId(deviceProfileId); + } + @Override public void deleteOtaPackagesByTenantId(TenantId tenantId) { log.trace("Executing deleteOtaPackagesByTenantId, tenantId [{}]", tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java index ef8740030c..a4ad6dc8c1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java @@ -16,11 +16,14 @@ package org.thingsboard.server.dao.ota; import org.thingsboard.server.common.data.OtaPackage; +import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.Dao; -import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityWithDataDao; public interface OtaPackageDao extends Dao, TenantEntityWithDataDao { Long sumDataSizeByTenantId(TenantId tenantId); + + boolean existsByDeviceProfileId(DeviceProfileId deviceProfileId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java index 98309b9e51..969fe0ec54 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java @@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.OtaPackage; +import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.ota.OtaPackageDao; import org.thingsboard.server.dao.model.sql.OtaPackageEntity; @@ -48,4 +49,10 @@ public class JpaOtaPackageDao extends JpaAbstractSearchTextDao { @Query(value = "SELECT COALESCE(SUM(ota.data_size), 0) FROM ota_package ota WHERE ota.tenant_id = :tenantId AND ota.data IS NOT NULL", nativeQuery = true) Long sumDataSizeByTenantId(@Param("tenantId") UUID tenantId); + + boolean existsByDeviceProfileId(UUID deviceProfileId); + } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index 8fcadcd812..0df2d9e6b6 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -487,8 +487,10 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { thrown.expectMessage("The otaPackage referenced by the device profile cannot be deleted!"); otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); } finally { - deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); + savedDeviceProfile.setFirmwareId(null); + deviceProfileService.saveDeviceProfile(savedDeviceProfile); otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); + deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); } } From 35528e687a6685bc6df7f3969de56b64dacf8b31 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Mon, 31 Jan 2022 13:21:59 +0200 Subject: [PATCH 2/5] Add test for deleting device profile referenced by OTA --- .../dao/service/AbstractServiceTest.java | 22 +++++++++++++++++++ .../service/BaseDeviceProfileServiceTest.java | 16 +++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 2d4fd72179..b4a6920cd8 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -33,14 +33,18 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Event; +import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.HasId; 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.dao.alarm.AlarmService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.audit.AuditLogLevelFilter; @@ -70,6 +74,7 @@ import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetsBundleService; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.Comparator; import java.util.HashMap; import java.util.Map; @@ -253,4 +258,21 @@ public abstract class AbstractServiceTest { edge.setCloudEndpoint("http://localhost:8080"); return edge; } + + protected OtaPackage constructDefaultOtaPackage(TenantId tenantId, DeviceProfileId deviceProfileId) { + OtaPackage firmware = new OtaPackage(); + firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(OtaPackageType.FIRMWARE); + firmware.setTitle("My firmware"); + firmware.setVersion("3.3.3"); + firmware.setFileName("filename.txt"); + firmware.setContentType("text/plain"); + firmware.setChecksumAlgorithm(ChecksumAlgorithm.SHA256); + firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"); + firmware.setData(ByteBuffer.wrap(new byte[]{1})); + firmware.setDataSize(1L); + return firmware; + } + } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java index cfd7923969..80d1ae809f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java @@ -31,8 +31,8 @@ import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.exception.DataValidationException; @@ -45,6 +45,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.stream.Collectors; +import static org.junit.Assert.assertThrows; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -252,6 +253,19 @@ public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest { deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); } + @Test + public void testDeleteDeviceProfileWithExistingOta() { + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile"); + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + + OtaPackage otaPackage = constructDefaultOtaPackage(tenantId, savedDeviceProfile.getId()); + otaPackageService.saveOtaPackage(otaPackage); + + assertThrows("The device profile is referenced by OTA update package", DataValidationException.class, () -> { + deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); + }); + } + @Test public void testDeleteDeviceProfile() { DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile"); From f51a66b585f7af2811cc0abf09f0fcde95f9aad5 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Fri, 4 Feb 2022 18:06:40 +0200 Subject: [PATCH 3/5] Delete OTA update packages of device profile with cascade when this profile is deleted --- .../main/data/upgrade/3.3.3/schema_update.sql | 27 +++++++++++++++++++ .../install/ThingsboardInstallService.java | 3 +++ .../install/SqlDatabaseUpgradeService.java | 12 +++++++++ .../server/dao/ota/OtaPackageService.java | 3 --- .../dao/device/DeviceProfileServiceImpl.java | 3 --- .../server/dao/ota/BaseOtaPackageService.java | 5 ---- .../server/dao/ota/OtaPackageDao.java | 5 +--- .../server/dao/sql/ota/JpaOtaPackageDao.java | 7 ----- .../dao/sql/ota/OtaPackageRepository.java | 4 +-- .../main/resources/sql/schema-entities.sql | 6 ++++- .../service/BaseDeviceProfileServiceTest.java | 21 ++++++++------- .../service/BaseOtaPackageServiceTest.java | 3 --- .../test/resources/sql/system-test-psql.sql | 2 +- dao/src/test/resources/sql/system-test.sql | 2 +- 14 files changed, 63 insertions(+), 40 deletions(-) create mode 100644 application/src/main/data/upgrade/3.3.3/schema_update.sql diff --git a/application/src/main/data/upgrade/3.3.3/schema_update.sql b/application/src/main/data/upgrade/3.3.3/schema_update.sql new file mode 100644 index 0000000000..dbaecc245f --- /dev/null +++ b/application/src/main/data/upgrade/3.3.3/schema_update.sql @@ -0,0 +1,27 @@ +-- +-- 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. +-- + +DO +$$ + BEGIN + IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'fk_device_profile_ota_package') THEN + ALTER TABLE ota_package + ADD CONSTRAINT fk_device_profile_ota_package + FOREIGN KEY (device_profile_id) REFERENCES device_profile (id) + ON DELETE CASCADE; + END IF; + END; +$$; diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 02bc87aaf9..046ce59b19 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -216,6 +216,9 @@ public class ThingsboardInstallService { dataUpdateService.updateData("3.3.2"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); + case "3.3.3": + log.info("Upgrading ThingsBoard from version 3.3.3 to 3.4.0 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.3.3"); break; //TODO update CacheCleanupService on the next version upgrade diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index eef29026ba..8872c95c5a 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -488,6 +488,18 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.3.3": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.3", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + log.info("Updating schema settings..."); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004000;"); + log.info("Schema updated"); + } catch (Exception e) { + log.error("Failed to update schema", e); + } + break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java index 638851f05d..b14653b1d0 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java @@ -51,7 +51,4 @@ public interface OtaPackageService { void deleteOtaPackagesByTenantId(TenantId tenantId); long sumDataSizeByTenantId(TenantId tenantId); - - boolean existsByDeviceProfileId(DeviceProfileId deviceProfileId); - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index c80834bfb6..18a8a1ecde 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -218,9 +218,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D if (deviceProfile != null && deviceProfile.isDefault()) { throw new DataValidationException("Deletion of Default Device Profile is prohibited!"); } - if (otaPackageService.existsByDeviceProfileId(deviceProfileId)) { - throw new DataValidationException("The device profile is referenced by OTA update package"); - } this.removeDeviceProfile(tenantId, deviceProfile); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java index c879fe6fdd..205b2c447b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java @@ -223,11 +223,6 @@ public class BaseOtaPackageService implements OtaPackageService { return otaPackageDao.sumDataSizeByTenantId(tenantId); } - @Override - public boolean existsByDeviceProfileId(DeviceProfileId deviceProfileId) { - return otaPackageDao.existsByDeviceProfileId(deviceProfileId); - } - @Override public void deleteOtaPackagesByTenantId(TenantId tenantId) { log.trace("Executing deleteOtaPackagesByTenantId, tenantId [{}]", tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java index a4ad6dc8c1..ef8740030c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java @@ -16,14 +16,11 @@ package org.thingsboard.server.dao.ota; import org.thingsboard.server.common.data.OtaPackage; -import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.Dao; +import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityWithDataDao; public interface OtaPackageDao extends Dao, TenantEntityWithDataDao { Long sumDataSizeByTenantId(TenantId tenantId); - - boolean existsByDeviceProfileId(DeviceProfileId deviceProfileId); - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java index 969fe0ec54..98309b9e51 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java @@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.OtaPackage; -import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.ota.OtaPackageDao; import org.thingsboard.server.dao.model.sql.OtaPackageEntity; @@ -49,10 +48,4 @@ public class JpaOtaPackageDao extends JpaAbstractSearchTextDao { @Query(value = "SELECT COALESCE(SUM(ota.data_size), 0) FROM ota_package ota WHERE ota.tenant_id = :tenantId AND ota.data IS NOT NULL", nativeQuery = true) Long sumDataSizeByTenantId(@Param("tenantId") UUID tenantId); - - boolean existsByDeviceProfileId(UUID deviceProfileId); - } diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 4fc5fbaebc..6cb8e84c45 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -211,7 +211,6 @@ CREATE TABLE IF NOT EXISTS ota_package ( additional_info varchar, search_text varchar(255), CONSTRAINT ota_package_tenant_title_version_unq_key UNIQUE (tenant_id, title, version) --- CONSTRAINT fk_device_profile_firmware FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS device_profile ( @@ -241,6 +240,11 @@ CREATE TABLE IF NOT EXISTS device_profile ( CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES ota_package(id) ); +ALTER TABLE ota_package + ADD CONSTRAINT fk_device_profile_ota_package + FOREIGN KEY (device_profile_id) REFERENCES device_profile (id) + ON DELETE CASCADE; + -- We will use one-to-many relation in the first release and extend this feature in case of user requests -- CREATE TABLE IF NOT EXISTS device_profile_firmware ( -- device_profile_id uuid NOT NULL, diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java index 80d1ae809f..c2caf3ea80 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java @@ -31,8 +31,8 @@ import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.exception.DataValidationException; @@ -45,7 +45,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.stream.Collectors; -import static org.junit.Assert.assertThrows; +import static org.assertj.core.api.Assertions.assertThat; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -254,16 +254,19 @@ public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest { } @Test - public void testDeleteDeviceProfileWithExistingOta() { + public void testDeleteDeviceProfileWithExistingOta_cascadeDelete() { DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile"); - DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + deviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + OtaPackage otaPackage = constructDefaultOtaPackage(tenantId, deviceProfile.getId()); + otaPackage = otaPackageService.saveOtaPackage(otaPackage); + + assertThat(deviceProfileService.findDeviceProfileById(tenantId, deviceProfile.getId())).isNotNull(); + assertThat(otaPackageService.findOtaPackageById(tenantId, otaPackage.getId())).isNotNull(); - OtaPackage otaPackage = constructDefaultOtaPackage(tenantId, savedDeviceProfile.getId()); - otaPackageService.saveOtaPackage(otaPackage); + deviceProfileService.deleteDeviceProfile(tenantId, deviceProfile.getId()); - assertThrows("The device profile is referenced by OTA update package", DataValidationException.class, () -> { - deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); - }); + assertThat(deviceProfileService.findDeviceProfileById(tenantId, deviceProfile.getId())).isNull(); + assertThat(otaPackageService.findOtaPackageById(tenantId, otaPackage.getId())).isNull(); } @Test diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index 0df2d9e6b6..b890c71453 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -487,9 +487,6 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { thrown.expectMessage("The otaPackage referenced by the device profile cannot be deleted!"); otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); } finally { - savedDeviceProfile.setFirmwareId(null); - deviceProfileService.saveDeviceProfile(savedDeviceProfile); - otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); } } diff --git a/dao/src/test/resources/sql/system-test-psql.sql b/dao/src/test/resources/sql/system-test-psql.sql index 16dcb8c3ae..177f838bb1 100644 --- a/dao/src/test/resources/sql/system-test-psql.sql +++ b/dao/src/test/resources/sql/system-test-psql.sql @@ -1,2 +1,2 @@ --PostgreSQL specific truncate to fit constraints -TRUNCATE TABLE device_credentials, device, device_profile, rule_node_state, rule_node, rule_chain; \ No newline at end of file +TRUNCATE TABLE device_credentials, device, device_profile, ota_package, rule_node_state, rule_node, rule_chain; \ No newline at end of file diff --git a/dao/src/test/resources/sql/system-test.sql b/dao/src/test/resources/sql/system-test.sql index 68a0e0efa3..d673548fb0 100644 --- a/dao/src/test/resources/sql/system-test.sql +++ b/dao/src/test/resources/sql/system-test.sql @@ -1,6 +1,6 @@ TRUNCATE TABLE device_credentials; TRUNCATE TABLE device; -TRUNCATE TABLE device_profile; +TRUNCATE TABLE device_profile CASCADE; TRUNCATE TABLE rule_node_state; TRUNCATE TABLE rule_node; TRUNCATE TABLE rule_chain; \ No newline at end of file From ef129d2648417cde055a7b131feea4bd01e0ba8a Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Mon, 7 Feb 2022 11:42:26 +0200 Subject: [PATCH 4/5] Fix upgrade --- .../thingsboard/server/install/ThingsboardInstallService.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index d45046737e..2415fc7394 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -216,11 +216,9 @@ public class ThingsboardInstallService { dataUpdateService.updateData("3.3.2"); case "3.3.3": log.info("Upgrading ThingsBoard from version 3.3.3 to 3.3.4 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.3.3"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); - case "3.3.3": - log.info("Upgrading ThingsBoard from version 3.3.3 to 3.4.0 ..."); - databaseEntitiesUpgradeService.upgradeDatabase("3.3.3"); break; //TODO update CacheCleanupService on the next version upgrade From 53323077aed5ec15ff3980915478f4b1b3bb604a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 7 Mar 2022 14:33:42 +0200 Subject: [PATCH 5/5] Update delete device profile warning text to mention associated OTA updates --- application/src/main/data/upgrade/3.3.3/schema_update.sql | 2 +- .../thingsboard/server/install/ThingsboardInstallService.java | 1 - ui-ngx/src/assets/locale/locale.constant-en_US.json | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.3/schema_update.sql b/application/src/main/data/upgrade/3.3.3/schema_update.sql index dbaecc245f..4183fb687a 100644 --- a/application/src/main/data/upgrade/3.3.3/schema_update.sql +++ b/application/src/main/data/upgrade/3.3.3/schema_update.sql @@ -1,5 +1,5 @@ -- --- Copyright © 2016-2021 The Thingsboard Authors +-- Copyright © 2016-2022 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. diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index edf5c88420..2415fc7394 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -218,7 +218,6 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 3.3.3 to 3.3.4 ..."); databaseEntitiesUpgradeService.upgradeDatabase("3.3.3"); log.info("Updating system data..."); - databaseEntitiesUpgradeService.upgradeDatabase("3.3.3"); systemDataLoaderService.updateSystemWidgets(); break; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index d593fd0c08..aab433c992 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1119,9 +1119,9 @@ "mobile-dashboard-hint": "Used by mobile application as a device details dashboard", "select-queue-hint": "Select from a drop-down list.", "delete-device-profile-title": "Are you sure you want to delete the device profile '{{deviceProfileName}}'?", - "delete-device-profile-text": "Be careful, after the confirmation the device profile and all related data will become unrecoverable.", + "delete-device-profile-text": "Be careful, after the confirmation the device profile and all related data including associated OTA updates will become unrecoverable.", "delete-device-profiles-title": "Are you sure you want to delete { count, plural, 1 {1 device profile} other {# device profiles} }?", - "delete-device-profiles-text": "Be careful, after the confirmation all selected device profiles will be removed and all related data will become unrecoverable.", + "delete-device-profiles-text": "Be careful, after the confirmation all selected device profiles will be removed and all related data including associated OTA updates will become unrecoverable.", "set-default-device-profile-title": "Are you sure you want to make the device profile '{{deviceProfileName}}' default?", "set-default-device-profile-text": "After the confirmation the device profile will be marked as default and will be used for new devices with no profile specified.", "no-device-profiles-found": "No device profiles found.",