Add support for pollingTime overrides (#2533)

* Add support for pollingTime overrides

* the current format HH:mm:ss is still supported
* add option for deviation percent (HH:mm:ss~\d{1,2}%) which allows the system to do some randomizing of the poll interval
* add support for overriding default polling time interval for devices matching some RSQL filters (in order), e.g. 01:00:00~10%, group == 'eu' -> 00:02:00~15%, status != in_sync -> 00:05:00
* IMPORTANT: overdue time is calculated according to the default polling time. So, the overdue status might be incorrect for targets with overridden poll interval

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>

* Remove min polling time from the tenant config - it is a system configuration

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>

* Add support for bigger poll intervals and overdue + duration format config support

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>

---------

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-07-07 16:33:55 +03:00
committed by GitHub
parent baab05f009
commit 7f97d6f441
31 changed files with 664 additions and 514 deletions

View File

@@ -139,24 +139,7 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest {
*/
@Test
void getPollingTimePermissionsCheck() {
assertPermissions(() -> controllerManagement.getPollingTime(), List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
}
/**
* Tests ControllerManagement#getMinPollingTime() method
*/
@Test
void getMinPollingTimePermissionsCheck() {
assertPermissions(() -> controllerManagement.getMinPollingTime(), List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
}
/**
* Tests ControllerManagement#getMaxPollingTime() method
*/
@Test
void getMaintenanceWindowPollCountPermissionsCheck() {
assertPermissions(() -> controllerManagement.getMaintenanceWindowPollCount(),
List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
assertPermissions(() -> controllerManagement.getPollingTime(null), List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
}
/**
@@ -168,7 +151,7 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest {
action.setId(1L);
assertPermissions(() -> {
try {
controllerManagement.getPollingTimeForAction(action);
controllerManagement.getPollingTimeForAction(action.getTarget(), action);
} catch (final CancelActionNotAllowedException e) {
// expected since action is not found
}

View File

@@ -51,7 +51,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
// get the configuration from the system management
final TenantConfigurationValue<String> defaultConfigValue = tenantConfigurationManagement.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class);
TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class);
assertThat(defaultConfigValue.isGlobal()).isTrue();
assertThat(defaultConfigValue.getValue()).isEqualTo(envPropertyDefault);
@@ -60,11 +60,11 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
final String newConfigurationValue = "thisIsAnotherTokenName";
assertThat(newConfigurationValue).isNotEqualTo(defaultConfigValue.getValue());
tenantConfigurationManagement.addOrUpdateConfiguration(
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, newConfigurationValue);
TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, newConfigurationValue);
// verify that new configuration value is used
final TenantConfigurationValue<String> updatedConfigurationValue = tenantConfigurationManagement
.getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class);
.getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class);
assertThat(updatedConfigurationValue.isGlobal()).isFalse();
assertThat(updatedConfigurationValue.getValue()).isEqualTo(newConfigurationValue);
@@ -76,7 +76,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void updateTenantSpecificConfiguration() {
final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY;
final String configKey = TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY;
final String value1 = "firstValue";
final String value2 = "secondValue";
@@ -95,14 +95,14 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
@Test
void batchUpdateTenantSpecificConfiguration() {
Map<String, Serializable> configuration = new HashMap<>() {{
put(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, "token_123");
put(TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, "token_123");
put(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, true);
}};
// add value first
tenantConfigurationManagement.addOrUpdateConfiguration(configuration);
assertThat(tenantConfigurationManagement.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue())
TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue())
.isEqualTo("token_123");
assertThat(
tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue())
@@ -114,7 +114,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void storeAndUpdateTenantSpecificConfigurationAsBoolean() {
final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
final String configKey = TenantConfigurationKey.AUTHENTICATION_HEADER_ENABLED;
final Boolean value1 = true;
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value1);
assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, Boolean.class).getValue()).isEqualTo(value1);
@@ -128,7 +128,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void wrongTenantConfigurationValueTypeThrowsException() {
final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
final String configKey = TenantConfigurationKey.AUTHENTICATION_HEADER_ENABLED;
final String value1 = "thisIsNotABoolean";
// add value as String
@@ -143,9 +143,9 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
@Test
void batchWrongTenantConfigurationValueTypeThrowsException() {
final Map<String, Serializable> configuration = new HashMap<>() {{
put(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, "token_123");
put(TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, "token_123");
put(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, true);
put(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, "wrong");
put(TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED, "wrong");
}};
try {
@@ -154,7 +154,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
} catch (final TenantConfigurationValidatorException e) {
assertThat(
tenantConfigurationManagement.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue())
TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue())
.isNotEqualTo("token_123");
assertThat(
tenantConfigurationManagement.getConfigurationValue(
@@ -168,7 +168,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void deleteConfigurationReturnNullConfiguration() {
final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY;
final String configKey = TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY;
// gateway token does not have default value so no configuration value should be available
final String defaultConfigValue = tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue();
@@ -195,7 +195,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void storesIntegerWhenStringIsExpected() {
final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY;
final String configKey = TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY;
final Integer wrongDatType = 123;
assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDatType))
.as("Should not have worked as integer is not a string")
@@ -207,7 +207,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void storesIntegerWhenBooleanIsExpected() {
final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED;
final String configKey = TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED;
final Integer wrongDataType = 123;
assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataType))
.as("Should not have worked as integer is not a boolean")
@@ -219,7 +219,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void storesIntegerWhenPollingIntervalIsExpected() {
final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
final String configKey = TenantConfigurationKey.POLLING_TIME;
final Integer wrongDataType = 123;
assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataType))
.as("Should not have worked as integer is not a time field")
@@ -231,7 +231,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void storesWrongFormattedStringAsPollingInterval() {
final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
final String configKey = TenantConfigurationKey.POLLING_TIME;
final String wrongFormatted = "wrongFormatted";
assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongFormatted))
.as("should not have worked as string is not a time field")
@@ -243,10 +243,9 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void storesTooSmallDurationAsPollingInterval() {
final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
final String configKey = TenantConfigurationKey.POLLING_TIME;
final String tooSmallDuration = DurationHelper
.durationToFormattedString(DurationHelper.getDurationByTimeValues(0, 0, 1));
final String tooSmallDuration = DurationHelper.toString(getDurationByTimeValues(0, 0, 1));
assertThatThrownBy(() -> tenantConfigurationManagement.addOrUpdateConfiguration(configKey, tooSmallDuration))
.as("Should not have worked as string has an invalid format")
.isInstanceOf(TenantConfigurationValidatorException.class);
@@ -257,15 +256,15 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void storesCorrectDurationAsPollingInterval() {
final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
final String configKey = TenantConfigurationKey.POLLING_TIME;
final Duration duration = DurationHelper.getDurationByTimeValues(1, 2, 0);
final Duration duration = getDurationByTimeValues(1, 2, 0);
assertThat(duration).isEqualTo(Duration.ofHours(1).plusMinutes(2));
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, DurationHelper.durationToFormattedString(duration));
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, DurationHelper.toString(duration));
final String storedDurationString = tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue();
assertThat(duration).isEqualTo(DurationHelper.formattedStringToDuration(storedDurationString));
assertThat(duration).isEqualTo(DurationHelper.fromString(storedDurationString));
}
/**
@@ -274,7 +273,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
@Test
void requestConfigValueWithWrongType() {
assertThatThrownBy(() -> tenantConfigurationManagement.getConfigurationValue(
TenantConfigurationKey.POLLING_TIME_INTERVAL, Serializable.class))
TenantConfigurationKey.POLLING_TIME, Serializable.class))
.isInstanceOf(TenantConfigurationValidatorException.class);
}
@@ -297,7 +296,7 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
*/
@Test
void getTenantConfigurationKeyByName() {
final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
final String configKey = TenantConfigurationKey.POLLING_TIME;
assertThat(tenantConfigurationProperties.fromKeyName(configKey).getKeyName()).isEqualTo(configKey);
}
@@ -311,4 +310,8 @@ class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest imple
.as("Expected InvalidTenantConfigurationKeyException for tenant configuration key which is not declared")
.isInstanceOf(InvalidTenantConfigurationKeyException.class);
}
private static Duration getDurationByTimeValues(final long hours, final long minutes, final long seconds) {
return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds);
}
}

View File

@@ -411,9 +411,9 @@ class RsqlUtilityTest {
VirtualPropertyReplacer setupMacroLookup() {
when(securityContext.runAsSystem(Mockito.any())).thenAnswer(a -> ((Callable<?>) a.getArgument(0)).call());
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class))
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME, String.class))
.thenReturn(TEST_POLLING_TIME_INTERVAL);
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class))
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME, String.class))
.thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL);
return macroResolver;

View File

@@ -54,9 +54,9 @@ class VirtualPropertyResolverTest {
@BeforeEach
void before() {
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class))
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME, String.class))
.thenReturn(TEST_POLLING_TIME_INTERVAL);
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class))
when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME, String.class))
.thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL);
}