Commit 4d4ca9b723f295b798448ddde1d40d56dd3f5a81

Authored by YevhenBondarenko
Committed by Andrew Shvayka
1 parent fd8dee0a

firmware tests and validation improvements

... ... @@ -63,6 +63,7 @@ CREATE TABLE IF NOT EXISTS firmware (
63 63 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
64 64 created_time bigint NOT NULL,
65 65 tenant_id uuid NOT NULL,
  66 + device_profile_id uuid,
66 67 type varchar(32) NOT NULL,
67 68 title varchar(255) NOT NULL,
68 69 version varchar(255) NOT NULL,
... ... @@ -78,10 +79,12 @@ CREATE TABLE IF NOT EXISTS firmware (
78 79 );
79 80
80 81 ALTER TABLE device_profile
81   - ADD COLUMN IF NOT EXISTS firmware_id uuid;
  82 + ADD COLUMN IF NOT EXISTS firmware_id uuid,
  83 + ADD COLUMN IF NOT EXISTS software_id uuid;
82 84
83 85 ALTER TABLE device
84   - ADD COLUMN IF NOT EXISTS firmware_id uuid;
  86 + ADD COLUMN IF NOT EXISTS firmware_id uuid,
  87 + ADD COLUMN IF NOT EXISTS software_id uuid;
85 88
86 89 DO $$
87 90 BEGIN
... ... @@ -91,11 +94,23 @@ DO $$
91 94 FOREIGN KEY (firmware_id) REFERENCES firmware(id);
92 95 END IF;
93 96
  97 + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_software_device_profile') THEN
  98 + ALTER TABLE device_profile
  99 + ADD CONSTRAINT fk_software_device_profile
  100 + FOREIGN KEY (firmware_id) REFERENCES firmware(id);
  101 + END IF;
  102 +
94 103 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN
95 104 ALTER TABLE device
96 105 ADD CONSTRAINT fk_firmware_device
97 106 FOREIGN KEY (firmware_id) REFERENCES firmware(id);
98 107 END IF;
  108 +
  109 + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_software_device') THEN
  110 + ALTER TABLE device
  111 + ADD CONSTRAINT fk_software_device
  112 + FOREIGN KEY (firmware_id) REFERENCES firmware(id);
  113 + END IF;
99 114 END;
100 115 $$;
101 116
... ...
... ... @@ -56,6 +56,7 @@ import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfilePr
56 56 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
57 57 import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
58 58 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  59 +import org.thingsboard.server.common.data.firmware.FirmwareType;
59 60 import org.thingsboard.server.common.data.id.DeviceProfileId;
60 61 import org.thingsboard.server.common.data.id.TenantId;
61 62 import org.thingsboard.server.common.data.page.PageData;
... ... @@ -405,9 +406,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
405 406 if (firmware == null) {
406 407 throw new DataValidationException("Can't assign non-existent firmware!");
407 408 }
  409 + if (!firmware.getType().equals(FirmwareType.FIRMWARE)) {
  410 + throw new DataValidationException("Can't assign firmware with type: " + firmware.getType());
  411 + }
408 412 if (firmware.getData() == null) {
409 413 throw new DataValidationException("Can't assign firmware with empty data!");
410 414 }
  415 + if (!firmware.getDeviceProfileId().equals(deviceProfile.getId())) {
  416 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  417 + }
411 418 }
412 419
413 420 if (deviceProfile.getSoftwareId() != null) {
... ... @@ -415,9 +422,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
415 422 if (software == null) {
416 423 throw new DataValidationException("Can't assign non-existent software!");
417 424 }
  425 + if (!software.getType().equals(FirmwareType.SOFTWARE)) {
  426 + throw new DataValidationException("Can't assign software with type: " + software.getType());
  427 + }
418 428 if (software.getData() == null) {
419 429 throw new DataValidationException("Can't assign software with empty data!");
420 430 }
  431 + if (!software.getDeviceProfileId().equals(deviceProfile.getId())) {
  432 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  433 + }
421 434 }
422 435 }
423 436
... ...
... ... @@ -51,6 +51,7 @@ import org.thingsboard.server.common.data.device.data.DeviceData;
51 51 import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration;
52 52 import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration;
53 53 import org.thingsboard.server.common.data.edge.Edge;
  54 +import org.thingsboard.server.common.data.firmware.FirmwareType;
54 55 import org.thingsboard.server.common.data.id.CustomerId;
55 56 import org.thingsboard.server.common.data.id.DeviceId;
56 57 import org.thingsboard.server.common.data.id.DeviceProfileId;
... ... @@ -683,6 +684,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
683 684 if (firmware == null) {
684 685 throw new DataValidationException("Can't assign non-existent firmware!");
685 686 }
  687 + if (!firmware.getType().equals(FirmwareType.FIRMWARE)) {
  688 + throw new DataValidationException("Can't assign firmware with type: " + firmware.getType());
  689 + }
686 690 if (firmware.getData() == null) {
687 691 throw new DataValidationException("Can't assign firmware with empty data!");
688 692 }
... ... @@ -696,6 +700,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
696 700 if (software == null) {
697 701 throw new DataValidationException("Can't assign non-existent software!");
698 702 }
  703 + if (!software.getType().equals(FirmwareType.SOFTWARE)) {
  704 + throw new DataValidationException("Can't assign software with type: " + software.getType());
  705 + }
699 706 if (software.getData() == null) {
700 707 throw new DataValidationException("Can't assign software with empty data!");
701 708 }
... ...
... ... @@ -191,6 +191,7 @@ public class BaseFirmwareService implements FirmwareService {
191 191 protected void validateUpdate(TenantId tenantId, FirmwareInfo firmware) {
192 192 FirmwareInfo firmwareOld = firmwareInfoDao.findById(tenantId, firmware.getUuidId());
193 193
  194 + validateUpdateDeviceProfile(firmware, firmwareOld);
194 195 BaseFirmwareService.validateUpdate(firmware, firmwareOld);
195 196 }
196 197 };
... ... @@ -247,6 +248,7 @@ public class BaseFirmwareService implements FirmwareService {
247 248 protected void validateUpdate(TenantId tenantId, Firmware firmware) {
248 249 Firmware firmwareOld = firmwareDao.findById(tenantId, firmware.getUuidId());
249 250
  251 + validateUpdateDeviceProfile(firmware, firmwareOld);
250 252 BaseFirmwareService.validateUpdate(firmware, firmwareOld);
251 253
252 254 if (firmwareOld.getData() != null && !firmwareOld.getData().equals(firmware.getData())) {
... ... @@ -255,11 +257,15 @@ public class BaseFirmwareService implements FirmwareService {
255 257 }
256 258 };
257 259
258   - private static void validateUpdate(FirmwareInfo firmware, FirmwareInfo firmwareOld) {
259   - if (!firmwareOld.getDeviceProfileId().equals(firmware.getDeviceProfileId())) {
260   - throw new DataValidationException("Updating firmware deviceProfile is prohibited!");
  260 + private void validateUpdateDeviceProfile(FirmwareInfo firmware, FirmwareInfo firmwareOld) {
  261 + if (firmwareOld.getDeviceProfileId() != null && !firmwareOld.getDeviceProfileId().equals(firmware.getDeviceProfileId())) {
  262 + if (firmwareInfoDao.isFirmwareUsed(firmwareOld.getId(), firmware.getType(), firmwareOld.getDeviceProfileId())) {
  263 + throw new DataValidationException("Can`t update deviceProfileId because firmware is already in use!");
  264 + }
261 265 }
  266 + }
262 267
  268 + private static void validateUpdate(FirmwareInfo firmware, FirmwareInfo firmwareOld) {
263 269 if (!firmwareOld.getType().equals(firmware.getType())) {
264 270 throw new DataValidationException("Updating type is prohibited!");
265 271 }
... ... @@ -303,9 +309,7 @@ public class BaseFirmwareService implements FirmwareService {
303 309 }
304 310 }
305 311
306   - if (firmwareInfo.getDeviceProfileId() == null) {
307   - throw new DataValidationException("Firmware should be assigned to deviceProfile!");
308   - } else {
  312 + if (firmwareInfo.getDeviceProfileId() != null) {
309 313 DeviceProfile deviceProfile = deviceProfileDao.findById(firmwareInfo.getTenantId(), firmwareInfo.getDeviceProfileId().getId());
310 314 if (deviceProfile == null) {
311 315 throw new DataValidationException("Firmware is referencing to non-existent device profile!");
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.firmware;
18 18 import org.thingsboard.server.common.data.FirmwareInfo;
19 19 import org.thingsboard.server.common.data.firmware.FirmwareType;
20 20 import org.thingsboard.server.common.data.id.DeviceProfileId;
  21 +import org.thingsboard.server.common.data.id.FirmwareId;
21 22 import org.thingsboard.server.common.data.id.TenantId;
22 23 import org.thingsboard.server.common.data.page.PageData;
23 24 import org.thingsboard.server.common.data.page.PageLink;
... ... @@ -31,4 +32,6 @@ public interface FirmwareInfoDao extends Dao<FirmwareInfo> {
31 32
32 33 PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink);
33 34
  35 + boolean isFirmwareUsed(FirmwareId firmwareId, FirmwareType type, DeviceProfileId deviceProfileId);
  36 +
34 37 }
... ...
... ... @@ -32,9 +32,9 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType;
32 32
33 33 import javax.persistence.Column;
34 34 import javax.persistence.Entity;
35   -import javax.persistence.Lob;
36 35 import javax.persistence.EnumType;
37 36 import javax.persistence.Enumerated;
  37 +import javax.persistence.Lob;
38 38 import javax.persistence.Table;
39 39 import java.nio.ByteBuffer;
40 40 import java.util.UUID;
... ... @@ -110,7 +110,9 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
110 110 this.createdTime = firmware.getCreatedTime();
111 111 this.setUuid(firmware.getUuidId());
112 112 this.tenantId = firmware.getTenantId().getId();
113   - this.deviceProfileId = firmware.getDeviceProfileId().getId();
  113 + if (firmware.getDeviceProfileId() != null) {
  114 + this.deviceProfileId = firmware.getDeviceProfileId().getId();
  115 + }
114 116 this.type = firmware.getType();
115 117 this.title = firmware.getTitle();
116 118 this.version = firmware.getVersion();
... ... @@ -138,7 +140,9 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
138 140 Firmware firmware = new Firmware(new FirmwareId(id));
139 141 firmware.setCreatedTime(createdTime);
140 142 firmware.setTenantId(new TenantId(tenantId));
141   - firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
  143 + if (deviceProfileId != null) {
  144 + firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
  145 + }
142 146 firmware.setType(type);
143 147 firmware.setTitle(title);
144 148 firmware.setVersion(version);
... ...
... ... @@ -109,7 +109,9 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
109 109 this.setUuid(firmware.getUuidId());
110 110 this.tenantId = firmware.getTenantId().getId();
111 111 this.type = firmware.getType();
112   - this.deviceProfileId = firmware.getDeviceProfileId().getId();
  112 + if (firmware.getDeviceProfileId() != null) {
  113 + this.deviceProfileId = firmware.getDeviceProfileId().getId();
  114 + }
113 115 this.title = firmware.getTitle();
114 116 this.version = firmware.getVersion();
115 117 this.fileName = firmware.getFileName();
... ... @@ -154,7 +156,9 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
154 156 FirmwareInfo firmware = new FirmwareInfo(new FirmwareId(id));
155 157 firmware.setCreatedTime(createdTime);
156 158 firmware.setTenantId(new TenantId(tenantId));
157   - firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
  159 + if (deviceProfileId != null) {
  160 + firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
  161 + }
158 162 firmware.setType(type);
159 163 firmware.setTitle(title);
160 164 firmware.setVersion(version);
... ...
... ... @@ -48,4 +48,13 @@ public interface FirmwareInfoRepository extends CrudRepository<FirmwareInfoEntit
48 48
49 49 @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE f.id = :id")
50 50 FirmwareInfoEntity findFirmwareInfoById(@Param("id") UUID id);
  51 +
  52 + @Query(value = "SELECT exists(SELECT * " +
  53 + "FROM device_profile AS dp " +
  54 + "LEFT JOIN device AS d ON dp.id = d.device_profile_id " +
  55 + "WHERE dp.id = :deviceProfileId AND " +
  56 + "(('FIRMWARE' = :type AND (dp.firmware_id = :firmwareId OR d.firmware_id = :firmwareId)) " +
  57 + "OR ('SOFTWARE' = :type AND (dp.software_id = :firmwareId or d.software_id = :firmwareId))))", nativeQuery = true)
  58 + boolean isFirmwareUsed(@Param("firmwareId") UUID firmwareId, @Param("deviceProfileId") UUID deviceProfileId, @Param("type") String type);
  59 +
51 60 }
... ...
... ... @@ -22,6 +22,7 @@ import org.springframework.stereotype.Component;
22 22 import org.thingsboard.server.common.data.FirmwareInfo;
23 23 import org.thingsboard.server.common.data.firmware.FirmwareType;
24 24 import org.thingsboard.server.common.data.id.DeviceProfileId;
  25 +import org.thingsboard.server.common.data.id.FirmwareId;
25 26 import org.thingsboard.server.common.data.id.TenantId;
26 27 import org.thingsboard.server.common.data.page.PageData;
27 28 import org.thingsboard.server.common.data.page.PageLink;
... ... @@ -85,4 +86,9 @@ public class JpaFirmwareInfoDao extends JpaAbstractSearchTextDao<FirmwareInfoEnt
85 86 Objects.toString(pageLink.getTextSearch(), ""),
86 87 DaoUtil.toPageable(pageLink)));
87 88 }
  89 +
  90 + @Override
  91 + public boolean isFirmwareUsed(FirmwareId firmwareId, FirmwareType type, DeviceProfileId deviceProfileId) {
  92 + return firmwareInfoRepository.isFirmwareUsed(firmwareId.getId(), deviceProfileId.getId(), type.name());
  93 + }
88 94 }
... ...
... ... @@ -162,7 +162,7 @@ CREATE TABLE IF NOT EXISTS firmware (
162 162 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
163 163 created_time bigint NOT NULL,
164 164 tenant_id uuid NOT NULL,
165   - device_profile_id uuid NOT NULL,
  165 + device_profile_id uuid ,
166 166 type varchar(32) NOT NULL,
167 167 title varchar(255) NOT NULL,
168 168 version varchar(255) NOT NULL,
... ...
... ... @@ -180,7 +180,7 @@ CREATE TABLE IF NOT EXISTS firmware (
180 180 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
181 181 created_time bigint NOT NULL,
182 182 tenant_id uuid NOT NULL,
183   - device_profile_id uuid NOT NULL,
  183 + device_profile_id uuid ,
184 184 type varchar(32) NOT NULL,
185 185 title varchar(255) NOT NULL,
186 186 version varchar(255) NOT NULL,
... ...
... ... @@ -175,24 +175,6 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
175 175 }
176 176
177 177 @Test
178   - public void testSaveFirmwareWithEmptyDeviceProfile() {
179   - Firmware firmware = new Firmware();
180   - firmware.setTenantId(tenantId);
181   - firmware.setType(FIRMWARE);
182   - firmware.setTitle(TITLE);
183   - firmware.setVersion(VERSION);
184   - firmware.setFileName(FILE_NAME);
185   - firmware.setContentType(CONTENT_TYPE);
186   - firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
187   - firmware.setChecksum(CHECKSUM);
188   - firmware.setData(DATA);
189   -
190   - thrown.expect(DataValidationException.class);
191   - thrown.expectMessage("Firmware should be assigned to deviceProfile!");
192   - firmwareService.saveFirmware(firmware);
193   - }
194   -
195   - @Test
196 178 public void testSaveFirmwareWithEmptyType() {
197 179 Firmware firmware = new Firmware();
198 180 firmware.setTenantId(tenantId);
... ... @@ -425,6 +407,39 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
425 407 }
426 408
427 409 @Test
  410 + public void testUpdateDeviceProfileIdWithReferenceByDevice() {
  411 + Firmware firmware = new Firmware();
  412 + firmware.setTenantId(tenantId);
  413 + firmware.setDeviceProfileId(deviceProfileId);
  414 + firmware.setType(FIRMWARE);
  415 + firmware.setTitle(TITLE);
  416 + firmware.setVersion(VERSION);
  417 + firmware.setFileName(FILE_NAME);
  418 + firmware.setContentType(CONTENT_TYPE);
  419 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  420 + firmware.setChecksum(CHECKSUM);
  421 + firmware.setData(DATA);
  422 + Firmware savedFirmware = firmwareService.saveFirmware(firmware);
  423 +
  424 + Device device = new Device();
  425 + device.setTenantId(tenantId);
  426 + device.setName("My device");
  427 + device.setDeviceProfileId(deviceProfileId);
  428 + device.setFirmwareId(savedFirmware.getId());
  429 + Device savedDevice = deviceService.saveDevice(device);
  430 +
  431 + try {
  432 + thrown.expect(DataValidationException.class);
  433 + thrown.expectMessage("Can`t update deviceProfileId because firmware is already in use!");
  434 + savedFirmware.setDeviceProfileId(null);
  435 + firmwareService.saveFirmware(savedFirmware);
  436 + } finally {
  437 + deviceService.deleteDevice(tenantId, savedDevice.getId());
  438 + firmwareService.deleteFirmware(tenantId, savedFirmware.getId());
  439 + }
  440 + }
  441 +
  442 + @Test
428 443 public void testDeleteFirmwareWithReferenceByDeviceProfile() {
429 444 DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Test Device Profile");
430 445 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
... ... @@ -456,6 +471,38 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
456 471 }
457 472
458 473 @Test
  474 + public void testUpdateDeviceProfileIdWithReferenceByDeviceProfile() {
  475 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Test Device Profile");
  476 + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
  477 +
  478 + Firmware firmware = new Firmware();
  479 + firmware.setTenantId(tenantId);
  480 + firmware.setDeviceProfileId(savedDeviceProfile.getId());
  481 + firmware.setType(FIRMWARE);
  482 + firmware.setTitle(TITLE);
  483 + firmware.setVersion(VERSION);
  484 + firmware.setFileName(FILE_NAME);
  485 + firmware.setContentType(CONTENT_TYPE);
  486 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  487 + firmware.setChecksum(CHECKSUM);
  488 + firmware.setData(DATA);
  489 + Firmware savedFirmware = firmwareService.saveFirmware(firmware);
  490 +
  491 + savedDeviceProfile.setFirmwareId(savedFirmware.getId());
  492 + deviceProfileService.saveDeviceProfile(savedDeviceProfile);
  493 +
  494 + try {
  495 + thrown.expect(DataValidationException.class);
  496 + thrown.expectMessage("Can`t update deviceProfileId because firmware is already in use!");
  497 + savedFirmware.setDeviceProfileId(null);
  498 + firmwareService.saveFirmware(savedFirmware);
  499 + } finally {
  500 + deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
  501 + firmwareService.deleteFirmware(tenantId, savedFirmware.getId());
  502 + }
  503 + }
  504 +
  505 + @Test
459 506 public void testFindFirmwareById() {
460 507 Firmware firmware = new Firmware();
461 508 firmware.setTenantId(tenantId);
... ...