Added service layer test with validation of scheduling config updates
This commit is contained in:
		
							parent
							
								
									bf83848076
								
							
						
					
					
						commit
						43b07c242f
					
				@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.cf.configuration.Argument;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ArgumentType;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingEvent;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ZoneGroupConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingZoneGroupConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.Output;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.OutputType;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey;
 | 
			
		||||
@ -701,8 +701,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
 | 
			
		||||
        // Zone group reporting config
 | 
			
		||||
        List<GeofencingEvent> reportEvents = Arrays.stream(GeofencingEvent.values()).toList();
 | 
			
		||||
 | 
			
		||||
        ZoneGroupConfiguration allowedCfg = new ZoneGroupConfiguration("allowedZone", reportEvents);
 | 
			
		||||
        ZoneGroupConfiguration restrictedCfg = new ZoneGroupConfiguration("restrictedZone", reportEvents);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedCfg = new GeofencingZoneGroupConfiguration("allowedZone", reportEvents);
 | 
			
		||||
        GeofencingZoneGroupConfiguration restrictedCfg = new GeofencingZoneGroupConfiguration("restrictedZone", reportEvents);
 | 
			
		||||
 | 
			
		||||
        cfg.setZoneGroupConfigurations(Map.of(
 | 
			
		||||
                "allowedZones", allowedCfg,
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.cf.configuration.ArgumentType;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingEvent;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ZoneGroupConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingZoneGroupConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.Output;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.OutputType;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey;
 | 
			
		||||
@ -337,8 +337,8 @@ public class GeofencingCalculatedFieldStateTest {
 | 
			
		||||
        config.setArguments(Map.of("latitude", argument1, "longitude", argument2, "allowedZones", argument3, "restrictedZones", argument4));
 | 
			
		||||
 | 
			
		||||
        List<GeofencingEvent> reportEvents = Arrays.stream(GeofencingEvent.values()).toList();
 | 
			
		||||
        ZoneGroupConfiguration allowedZoneGroupConfiguration = new ZoneGroupConfiguration("allowedZone", reportEvents);
 | 
			
		||||
        ZoneGroupConfiguration restrictedZoneGroupConfiguration = new ZoneGroupConfiguration("restrictedZone", reportEvents);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedZoneGroupConfiguration = new GeofencingZoneGroupConfiguration("allowedZone", reportEvents);
 | 
			
		||||
        GeofencingZoneGroupConfiguration restrictedZoneGroupConfiguration = new GeofencingZoneGroupConfiguration("restrictedZone", reportEvents);
 | 
			
		||||
        config.setZoneGroupConfigurations(Map.of("allowedZones", allowedZoneGroupConfiguration, "restrictedZones", restrictedZoneGroupConfiguration));
 | 
			
		||||
 | 
			
		||||
        config.setCreateRelationsWithMatchedZones(true);
 | 
			
		||||
 | 
			
		||||
@ -66,11 +66,9 @@ public interface CalculatedFieldConfiguration {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @JsonIgnore
 | 
			
		||||
    default void setScheduledUpdateIntervalSec(int scheduledUpdateIntervalSec) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @JsonIgnore
 | 
			
		||||
    default int getScheduledUpdateIntervalSec() {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
 | 
			
		||||
    private boolean createRelationsWithMatchedZones;
 | 
			
		||||
    private String zoneRelationType;
 | 
			
		||||
    private EntitySearchDirection zoneRelationDirection;
 | 
			
		||||
    private Map<String, ZoneGroupConfiguration> zoneGroupConfigurations;
 | 
			
		||||
    private Map<String, GeofencingZoneGroupConfiguration> zoneGroupConfigurations;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public CalculatedFieldType getType() {
 | 
			
		||||
@ -91,7 +91,7 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
 | 
			
		||||
        Set<String> usedPrefixes = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
        zoneGroupsArguments.forEach((zoneGroupName, zoneGroupArgument) -> {
 | 
			
		||||
            ZoneGroupConfiguration config = zoneGroupConfigurations.get(zoneGroupName);
 | 
			
		||||
            GeofencingZoneGroupConfiguration config = zoneGroupConfigurations.get(zoneGroupName);
 | 
			
		||||
            if (config == null) {
 | 
			
		||||
                throw new IllegalArgumentException("Zone group configuration is not configured for '" + zoneGroupName + "' argument!");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ import lombok.Data;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class ZoneGroupConfiguration {
 | 
			
		||||
public class GeofencingZoneGroupConfiguration {
 | 
			
		||||
 | 
			
		||||
    private final String reportTelemetryPrefix;
 | 
			
		||||
    private final List<GeofencingEvent> reportEvents;
 | 
			
		||||
@ -224,8 +224,8 @@ public class GeofencingCalculatedFieldConfigurationTest {
 | 
			
		||||
        allowedZonesArg.setRefDynamicSourceConfiguration(refDynamicSourceConfigurationMock);
 | 
			
		||||
        arguments.put("allowedZones", allowedZonesArg);
 | 
			
		||||
 | 
			
		||||
        ZoneGroupConfiguration allowedZoneConfiguration = new ZoneGroupConfiguration("allowedZone", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, ZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedZoneConfiguration = new GeofencingZoneGroupConfiguration("allowedZone", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, GeofencingZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(arguments);
 | 
			
		||||
        cfg.setZoneGroupConfigurations(zoneGroupConfigurations);
 | 
			
		||||
@ -268,9 +268,9 @@ public class GeofencingCalculatedFieldConfigurationTest {
 | 
			
		||||
        arguments.put("allowedZones", allowedZonesArg);
 | 
			
		||||
        arguments.put("restrictedZones", restrictedZonesArg);
 | 
			
		||||
 | 
			
		||||
        ZoneGroupConfiguration allowedZoneConfiguration = new ZoneGroupConfiguration("theSamePrefixTest", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        ZoneGroupConfiguration restrictedZoneConfiguration = new ZoneGroupConfiguration("theSamePrefixTest", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, ZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration, "restrictedZones", restrictedZoneConfiguration);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedZoneConfiguration = new GeofencingZoneGroupConfiguration("theSamePrefixTest", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        GeofencingZoneGroupConfiguration restrictedZoneConfiguration = new GeofencingZoneGroupConfiguration("theSamePrefixTest", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, GeofencingZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration, "restrictedZones", restrictedZoneConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(arguments);
 | 
			
		||||
        cfg.setZoneGroupConfigurations(zoneGroupConfigurations);
 | 
			
		||||
@ -292,8 +292,8 @@ public class GeofencingCalculatedFieldConfigurationTest {
 | 
			
		||||
        allowedZonesArg.setRefDynamicSourceConfiguration(refDynamicSourceConfigurationMock);
 | 
			
		||||
        arguments.put("allowedZones", allowedZonesArg);
 | 
			
		||||
 | 
			
		||||
        ZoneGroupConfiguration allowedZoneConfiguration = new ZoneGroupConfiguration("allowedZone", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, ZoneGroupConfiguration> zoneGroupConfigurations = Map.of("someOtherZones", allowedZoneConfiguration);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedZoneConfiguration = new GeofencingZoneGroupConfiguration("allowedZone", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, GeofencingZoneGroupConfiguration> zoneGroupConfigurations = Map.of("someOtherZones", allowedZoneConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(arguments);
 | 
			
		||||
        cfg.setZoneGroupConfigurations(zoneGroupConfigurations);
 | 
			
		||||
@ -315,8 +315,8 @@ public class GeofencingCalculatedFieldConfigurationTest {
 | 
			
		||||
        allowedZonesArg.setRefDynamicSourceConfiguration(refDynamicSourceConfigurationMock);
 | 
			
		||||
        arguments.put("allowedZones", allowedZonesArg);
 | 
			
		||||
 | 
			
		||||
        ZoneGroupConfiguration allowedZoneConfiguration = new ZoneGroupConfiguration("allowedZone", null);
 | 
			
		||||
        Map<String, ZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedZoneConfiguration = new GeofencingZoneGroupConfiguration("allowedZone", null);
 | 
			
		||||
        Map<String, GeofencingZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(arguments);
 | 
			
		||||
        cfg.setZoneGroupConfigurations(zoneGroupConfigurations);
 | 
			
		||||
@ -340,8 +340,8 @@ public class GeofencingCalculatedFieldConfigurationTest {
 | 
			
		||||
        allowedZonesArg.setRefDynamicSourceConfiguration(refDynamicSourceConfigurationMock);
 | 
			
		||||
        arguments.put("allowedZones", allowedZonesArg);
 | 
			
		||||
 | 
			
		||||
        ZoneGroupConfiguration allowedZoneConfiguration = new ZoneGroupConfiguration(reportTelemetryPrefix, Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, ZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedZoneConfiguration = new GeofencingZoneGroupConfiguration(reportTelemetryPrefix, Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, GeofencingZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(arguments);
 | 
			
		||||
        cfg.setZoneGroupConfigurations(zoneGroupConfigurations);
 | 
			
		||||
@ -365,8 +365,8 @@ public class GeofencingCalculatedFieldConfigurationTest {
 | 
			
		||||
        allowedZonesArg.setRefDynamicSourceConfiguration(refDynamicSourceConfigurationMock);
 | 
			
		||||
        arguments.put("allowedZones", allowedZonesArg);
 | 
			
		||||
 | 
			
		||||
        ZoneGroupConfiguration allowedZoneConfiguration = new ZoneGroupConfiguration("allowedZone", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, ZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedZoneConfiguration = new GeofencingZoneGroupConfiguration("allowedZone", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, GeofencingZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(arguments);
 | 
			
		||||
        cfg.setZoneGroupConfigurations(zoneGroupConfigurations);
 | 
			
		||||
@ -390,8 +390,8 @@ public class GeofencingCalculatedFieldConfigurationTest {
 | 
			
		||||
        allowedZonesArg.setRefDynamicSourceConfiguration(refDynamicSourceConfigurationMock);
 | 
			
		||||
        arguments.put("allowedZones", allowedZonesArg);
 | 
			
		||||
 | 
			
		||||
        ZoneGroupConfiguration allowedZoneConfiguration = new ZoneGroupConfiguration("allowedZone", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, ZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
        GeofencingZoneGroupConfiguration allowedZoneConfiguration = new GeofencingZoneGroupConfiguration("allowedZone", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        Map<String, GeofencingZoneGroupConfiguration> zoneGroupConfigurations = Map.of("allowedZones", allowedZoneConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(arguments);
 | 
			
		||||
        cfg.setZoneGroupConfigurations(zoneGroupConfigurations);
 | 
			
		||||
@ -448,7 +448,7 @@ public class GeofencingCalculatedFieldConfigurationTest {
 | 
			
		||||
        args.put("allowedZones", allowed);
 | 
			
		||||
        cfg.setArguments(args);
 | 
			
		||||
 | 
			
		||||
        var zc = new ZoneGroupConfiguration("gf_allowed", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        var zc = new GeofencingZoneGroupConfiguration("gf_allowed", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        cfg.setZoneGroupConfigurations(Map.of("allowedZones", zc));
 | 
			
		||||
 | 
			
		||||
        cfg.setCreateRelationsWithMatchedZones(true);
 | 
			
		||||
 | 
			
		||||
@ -28,18 +28,24 @@ import org.thingsboard.server.common.data.cf.CalculatedFieldType;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.Argument;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ArgumentType;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingEvent;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.GeofencingZoneGroupConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.Output;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.OutputType;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.RelationQueryDynamicSourceConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.SimpleCalculatedFieldConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CalculatedFieldId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelation;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 | 
			
		||||
import org.thingsboard.server.dao.cf.CalculatedFieldService;
 | 
			
		||||
import org.thingsboard.server.dao.device.DeviceService;
 | 
			
		||||
import org.thingsboard.server.dao.exception.DataValidationException;
 | 
			
		||||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
 | 
			
		||||
@ -51,6 +57,8 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest {
 | 
			
		||||
    private CalculatedFieldService calculatedFieldService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DeviceService deviceService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private TbTenantProfileCache tbTenantProfileCache;
 | 
			
		||||
 | 
			
		||||
    private ListeningExecutorService executor;
 | 
			
		||||
 | 
			
		||||
@ -90,6 +98,187 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest {
 | 
			
		||||
        calculatedFieldService.deleteCalculatedField(tenantId, savedCalculatedField.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveGeofencingCalculatedField_shouldNotChangeScheduledInterval() {
 | 
			
		||||
        // Arrange a device
 | 
			
		||||
        Device device = createTestDevice();
 | 
			
		||||
 | 
			
		||||
        // Build a valid Geofencing configuration
 | 
			
		||||
        GeofencingCalculatedFieldConfiguration cfg = new GeofencingCalculatedFieldConfiguration();
 | 
			
		||||
 | 
			
		||||
        // Coordinates: TS_LATEST, no dynamic source
 | 
			
		||||
        Argument lat = new Argument();
 | 
			
		||||
        lat.setRefEntityId(device.getId());
 | 
			
		||||
        lat.setRefEntityKey(new ReferencedEntityKey("latitude", ArgumentType.TS_LATEST, null));
 | 
			
		||||
 | 
			
		||||
        Argument lon = new Argument();
 | 
			
		||||
        lon.setRefEntityId(device.getId());
 | 
			
		||||
        lon.setRefEntityKey(new ReferencedEntityKey("longitude", ArgumentType.TS_LATEST, null));
 | 
			
		||||
 | 
			
		||||
        // Zone-group argument (ATTRIBUTE) — no DYNAMIC configuration, so no scheduling even if the scheduled interval is set
 | 
			
		||||
        Argument allowed = new Argument();
 | 
			
		||||
        lat.setRefEntityId(device.getId());
 | 
			
		||||
        allowed.setRefEntityKey(new ReferencedEntityKey("allowed", ArgumentType.ATTRIBUTE, null));
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(Map.of(
 | 
			
		||||
                GeofencingCalculatedFieldConfiguration.ENTITY_ID_LATITUDE_ARGUMENT_KEY, lat,
 | 
			
		||||
                GeofencingCalculatedFieldConfiguration.ENTITY_ID_LONGITUDE_ARGUMENT_KEY, lon,
 | 
			
		||||
                "allowed", allowed
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        // Matching zone-group configuration
 | 
			
		||||
        var geofencingZoneGroupConfiguration = new GeofencingZoneGroupConfiguration("gf_allowed", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        cfg.setZoneGroupConfigurations(Map.of("allowed", geofencingZoneGroupConfiguration));
 | 
			
		||||
 | 
			
		||||
        // Set a scheduled interval to some value
 | 
			
		||||
        cfg.setScheduledUpdateIntervalSec(600);
 | 
			
		||||
 | 
			
		||||
        // Create & save Calculated Field
 | 
			
		||||
        CalculatedField cf = new CalculatedField();
 | 
			
		||||
        cf.setTenantId(tenantId);
 | 
			
		||||
        cf.setEntityId(device.getId());
 | 
			
		||||
        cf.setType(CalculatedFieldType.GEOFENCING);
 | 
			
		||||
        cf.setName("GF clamp test");
 | 
			
		||||
        cf.setConfigurationVersion(0);
 | 
			
		||||
        cf.setConfiguration(cfg);
 | 
			
		||||
 | 
			
		||||
        CalculatedField saved = calculatedFieldService.save(cf);
 | 
			
		||||
 | 
			
		||||
        // Assert: the interval is saved, but scheduling is not enabled
 | 
			
		||||
        int savedInterval = saved.getConfiguration().getScheduledUpdateIntervalSec();
 | 
			
		||||
        boolean scheduledUpdateEnabled = saved.getConfiguration().isScheduledUpdateEnabled();
 | 
			
		||||
 | 
			
		||||
        assertThat(savedInterval).isEqualTo(600);
 | 
			
		||||
        assertThat(scheduledUpdateEnabled).isFalse();
 | 
			
		||||
 | 
			
		||||
        calculatedFieldService.deleteCalculatedField(tenantId, saved.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveGeofencingCalculatedField_shouldClampScheduledIntervalToTenantMin() {
 | 
			
		||||
        // Arrange a device
 | 
			
		||||
        Device device = createTestDevice();
 | 
			
		||||
 | 
			
		||||
        // Build a valid Geofencing configuration
 | 
			
		||||
        GeofencingCalculatedFieldConfiguration cfg = new GeofencingCalculatedFieldConfiguration();
 | 
			
		||||
 | 
			
		||||
        // Coordinates: TS_LATEST, no dynamic source
 | 
			
		||||
        Argument lat = new Argument();
 | 
			
		||||
        lat.setRefEntityId(device.getId());
 | 
			
		||||
        lat.setRefEntityKey(new ReferencedEntityKey("latitude", ArgumentType.TS_LATEST, null));
 | 
			
		||||
 | 
			
		||||
        Argument lon = new Argument();
 | 
			
		||||
        lon.setRefEntityId(device.getId());
 | 
			
		||||
        lon.setRefEntityKey(new ReferencedEntityKey("longitude", ArgumentType.TS_LATEST, null));
 | 
			
		||||
 | 
			
		||||
        // Zone-group argument (ATTRIBUTE) — make it DYNAMIC so scheduling is enabled
 | 
			
		||||
        Argument allowed = new Argument();
 | 
			
		||||
        allowed.setRefEntityKey(new ReferencedEntityKey("allowed", ArgumentType.ATTRIBUTE, null));
 | 
			
		||||
        var dynamicSourceConfiguration = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        dynamicSourceConfiguration.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        dynamicSourceConfiguration.setMaxLevel(1);
 | 
			
		||||
        dynamicSourceConfiguration.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
        allowed.setRefDynamicSourceConfiguration(dynamicSourceConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(Map.of(
 | 
			
		||||
                GeofencingCalculatedFieldConfiguration.ENTITY_ID_LATITUDE_ARGUMENT_KEY, lat,
 | 
			
		||||
                GeofencingCalculatedFieldConfiguration.ENTITY_ID_LONGITUDE_ARGUMENT_KEY, lon,
 | 
			
		||||
                "allowed", allowed
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        // Matching zone-group configuration
 | 
			
		||||
        var geofencingZoneGroupConfiguration = new GeofencingZoneGroupConfiguration("gf_allowed", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        cfg.setZoneGroupConfigurations(Map.of("allowed", geofencingZoneGroupConfiguration));
 | 
			
		||||
 | 
			
		||||
        // Enable scheduling with an interval below tenant min
 | 
			
		||||
        cfg.setScheduledUpdateIntervalSec(600);
 | 
			
		||||
 | 
			
		||||
        // Create & save Calculated Field
 | 
			
		||||
        CalculatedField cf = new CalculatedField();
 | 
			
		||||
        cf.setTenantId(tenantId);
 | 
			
		||||
        cf.setEntityId(device.getId());
 | 
			
		||||
        cf.setType(CalculatedFieldType.GEOFENCING);
 | 
			
		||||
        cf.setName("GF clamp test");
 | 
			
		||||
        cf.setConfigurationVersion(0);
 | 
			
		||||
        cf.setConfiguration(cfg);
 | 
			
		||||
 | 
			
		||||
        CalculatedField saved = calculatedFieldService.save(cf);
 | 
			
		||||
 | 
			
		||||
        // Assert: the interval is clamped up to tenant profile min
 | 
			
		||||
        int savedInterval = saved.getConfiguration().getScheduledUpdateIntervalSec();
 | 
			
		||||
 | 
			
		||||
         int min = tbTenantProfileCache.get(tenantId)
 | 
			
		||||
                 .getDefaultProfileConfiguration()
 | 
			
		||||
                 .getMinAllowedScheduledUpdateIntervalInSecForCF();
 | 
			
		||||
         assertThat(savedInterval).isEqualTo(min);
 | 
			
		||||
 | 
			
		||||
        calculatedFieldService.deleteCalculatedField(tenantId, saved.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveGeofencingCalculatedField_shouldUseScheduledIntervalFromConfig() {
 | 
			
		||||
        // Arrange a device
 | 
			
		||||
        Device device = createTestDevice();
 | 
			
		||||
 | 
			
		||||
        // Build a valid Geofencing configuration
 | 
			
		||||
        GeofencingCalculatedFieldConfiguration cfg = new GeofencingCalculatedFieldConfiguration();
 | 
			
		||||
 | 
			
		||||
        // Coordinates: TS_LATEST, no dynamic source
 | 
			
		||||
        Argument lat = new Argument();
 | 
			
		||||
        lat.setRefEntityId(device.getId());
 | 
			
		||||
        lat.setRefEntityKey(new ReferencedEntityKey("latitude", ArgumentType.TS_LATEST, null));
 | 
			
		||||
 | 
			
		||||
        Argument lon = new Argument();
 | 
			
		||||
        lon.setRefEntityId(device.getId());
 | 
			
		||||
        lon.setRefEntityKey(new ReferencedEntityKey("longitude", ArgumentType.TS_LATEST, null));
 | 
			
		||||
 | 
			
		||||
        // Zone-group argument (ATTRIBUTE) — make it DYNAMIC so scheduling is enabled
 | 
			
		||||
        Argument allowed = new Argument();
 | 
			
		||||
        allowed.setRefEntityKey(new ReferencedEntityKey("allowed", ArgumentType.ATTRIBUTE, null));
 | 
			
		||||
        var dynamicSourceConfiguration = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        dynamicSourceConfiguration.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        dynamicSourceConfiguration.setMaxLevel(1);
 | 
			
		||||
        dynamicSourceConfiguration.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
        allowed.setRefDynamicSourceConfiguration(dynamicSourceConfiguration);
 | 
			
		||||
 | 
			
		||||
        cfg.setArguments(Map.of(
 | 
			
		||||
                GeofencingCalculatedFieldConfiguration.ENTITY_ID_LATITUDE_ARGUMENT_KEY, lat,
 | 
			
		||||
                GeofencingCalculatedFieldConfiguration.ENTITY_ID_LONGITUDE_ARGUMENT_KEY, lon,
 | 
			
		||||
                "allowed", allowed
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        // Matching zone-group configuration
 | 
			
		||||
        var geofencingZoneGroupConfiguration = new GeofencingZoneGroupConfiguration("gf_allowed", Arrays.asList(GeofencingEvent.values()));
 | 
			
		||||
        cfg.setZoneGroupConfigurations(Map.of("allowed", geofencingZoneGroupConfiguration));
 | 
			
		||||
 | 
			
		||||
        // Get tenant profile min.
 | 
			
		||||
        int min = tbTenantProfileCache.get(tenantId)
 | 
			
		||||
                .getDefaultProfileConfiguration()
 | 
			
		||||
                .getMinAllowedScheduledUpdateIntervalInSecForCF();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Enable scheduling with an interval greater than tenant min
 | 
			
		||||
        int valueFromConfig = min + 100;
 | 
			
		||||
        cfg.setScheduledUpdateIntervalSec(valueFromConfig);
 | 
			
		||||
 | 
			
		||||
        // Create & save Calculated Field
 | 
			
		||||
        CalculatedField cf = new CalculatedField();
 | 
			
		||||
        cf.setTenantId(tenantId);
 | 
			
		||||
        cf.setEntityId(device.getId());
 | 
			
		||||
        cf.setType(CalculatedFieldType.GEOFENCING);
 | 
			
		||||
        cf.setName("GF no clamp test");
 | 
			
		||||
        cf.setConfigurationVersion(0);
 | 
			
		||||
        cf.setConfiguration(cfg);
 | 
			
		||||
 | 
			
		||||
        CalculatedField saved = calculatedFieldService.save(cf);
 | 
			
		||||
 | 
			
		||||
        // Assert: the interval is clamped up to tenant profile min (or stays >= original if already >= min)
 | 
			
		||||
        int savedInterval = saved.getConfiguration().getScheduledUpdateIntervalSec();
 | 
			
		||||
        assertThat(savedInterval).isEqualTo(valueFromConfig);
 | 
			
		||||
 | 
			
		||||
        calculatedFieldService.deleteCalculatedField(tenantId, saved.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveCalculatedFieldWithExistingName() {
 | 
			
		||||
        Device device = createTestDevice();
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user