Forbid change of device profile type or transport type when used by devices.

This commit is contained in:
Igor Kulikov 2020-09-03 18:54:08 +03:00
parent 06573211b3
commit d8ae8282a0
8 changed files with 85 additions and 5 deletions

View File

@ -62,9 +62,11 @@ import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
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.id.HasId;
import org.thingsboard.server.common.data.id.RuleChainId;
@ -315,10 +317,13 @@ public abstract class AbstractWebTest {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(name);
deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setTransportType(DeviceTransportType.DEFAULT);
deviceProfile.setDescription(name + " Test");
DeviceProfileData deviceProfileData = new DeviceProfileData();
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
DefaultDeviceProfileTransportConfiguration transportConfiguration = new DefaultDeviceProfileTransportConfiguration();
deviceProfileData.setConfiguration(configuration);
deviceProfileData.setTransportConfiguration(transportConfiguration);
deviceProfile.setProfileData(deviceProfileData);
deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));

View File

@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.page.PageData;
@ -154,13 +155,32 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Ignore
@Test
public void testSaveSameDeviceProfileWithDifferentType() throws Exception {
public void testChangeDeviceProfileTypeWithExistingDevices() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Device device = new Device();
device.setName("Test device");
device.setType("default");
device.setDeviceProfileId(savedDeviceProfile.getId());
doPost("/api/device", device, Device.class);
//TODO uncomment once we have other device types;
//savedDeviceProfile.setType(DeviceProfileType.LWM2M);
doPost("/api/deviceProfile", savedDeviceProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Changing type of device profile is prohibited")));
.andExpect(statusReason(containsString("Can't change device profile type because devices referenced it")));
}
@Test
public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Device device = new Device();
device.setName("Test device");
device.setType("default");
device.setDeviceProfileId(savedDeviceProfile.getId());
doPost("/api/device", device, Device.class);
savedDeviceProfile.setTransportType(DeviceTransportType.MQTT);
doPost("/api/deviceProfile", savedDeviceProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Can't change device profile transport type because devices referenced it")));
}
@Test

View File

@ -183,4 +183,5 @@ public interface DeviceDao extends Dao<Device> {
*/
ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id);
Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId);
}

View File

@ -58,6 +58,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
@Autowired
private DeviceProfileDao deviceProfileDao;
@Autowired
private DeviceDao deviceDao;
@Autowired
private TenantDao tenantDao;
@ -241,6 +244,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
if (StringUtils.isEmpty(deviceProfile.getName())) {
throw new DataValidationException("Device profile name should be specified!");
}
if (deviceProfile.getType() == null) {
throw new DataValidationException("Device profile type should be specified!");
}
if (deviceProfile.getTransportType() == null) {
throw new DataValidationException("Device profile transport type should be specified!");
}
if (deviceProfile.getTenantId() == null) {
throw new DataValidationException("Device profile should be assigned to tenant!");
} else {
@ -262,8 +271,20 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
DeviceProfile old = deviceProfileDao.findById(deviceProfile.getTenantId(), deviceProfile.getId().getId());
if (old == null) {
throw new DataValidationException("Can't update non existing device profile!");
} else if (!old.getType().equals(deviceProfile.getType())) {
throw new DataValidationException("Changing type of device profile is prohibited!");
}
boolean profileTypeChanged = !old.getType().equals(deviceProfile.getType());
boolean transportTypeChanged = !old.getTransportType().equals(deviceProfile.getTransportType());
if (profileTypeChanged || transportTypeChanged) {
Long profileDeviceCount = deviceDao.countDevicesByDeviceProfileId(deviceProfile.getTenantId(), deviceProfile.getId().getId());
if (profileDeviceCount > 0) {
String message = null;
if (profileTypeChanged) {
message = "Can't change device profile type because devices referenced it!";
} else if (transportTypeChanged) {
message = "Can't change device profile transport type because devices referenced it!";
}
throw new DataValidationException(message);
}
}
}
};

View File

@ -133,4 +133,6 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
DeviceEntity findByTenantIdAndId(UUID tenantId, UUID id);
Long countByDeviceProfileId(UUID deviceProfileId);
}

View File

@ -183,6 +183,11 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
return service.submit(() -> DaoUtil.getData(deviceRepository.findByTenantIdAndId(tenantId.getId(), id)));
}
@Override
public Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId) {
return deviceRepository.countByDeviceProfileId(deviceProfileId);
}
private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) {
List<EntitySubtype> list = Collections.emptyList();
if (types != null && !types.isEmpty()) {

View File

@ -30,9 +30,11 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.DeviceProfile;
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.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.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
@ -197,10 +199,13 @@ public abstract class AbstractServiceTest {
deviceProfile.setTenantId(tenantId);
deviceProfile.setName(name);
deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setTransportType(DeviceTransportType.DEFAULT);
deviceProfile.setDescription(name + " Test");
DeviceProfileData deviceProfileData = new DeviceProfileData();
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
DefaultDeviceProfileTransportConfiguration transportConfiguration = new DefaultDeviceProfileTransportConfiguration();
deviceProfileData.setConfiguration(configuration);
deviceProfileData.setTransportConfiguration(transportConfiguration);
deviceProfile.setProfileData(deviceProfileData);
deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));

View File

@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
@ -148,14 +149,34 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@Ignore
@Test(expected = DataValidationException.class)
public void testSaveSameDeviceProfileWithDifferentType() {
public void testChangeDeviceProfileTypeWithExistingDevices() {
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
Device device = new Device();
device.setTenantId(tenantId);
device.setName("Test device");
device.setType("default");
device.setDeviceProfileId(savedDeviceProfile.getId());
deviceService.saveDevice(device);
//TODO: once we have more profile types, we should test that we can not change profile type in runtime and uncomment the @Ignore.
// savedDeviceProfile.setType(DeviceProfileType.LWM2M);
deviceProfileService.saveDeviceProfile(savedDeviceProfile);
}
@Test(expected = DataValidationException.class)
public void testChangeDeviceProfileTransportTypeWithExistingDevices() {
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
Device device = new Device();
device.setTenantId(tenantId);
device.setName("Test device");
device.setType("default");
device.setDeviceProfileId(savedDeviceProfile.getId());
deviceService.saveDevice(device);
savedDeviceProfile.setTransportType(DeviceTransportType.MQTT);
deviceProfileService.saveDeviceProfile(savedDeviceProfile);
}
@Test(expected = DataValidationException.class)
public void testDeleteDeviceProfileWithExistingDevice() {
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile");