Move rollout executor related target management methods in executor (#2812)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-11-18 08:44:35 +02:00
committed by GitHub
parent 068e7cef69
commit 20bb41c51c
17 changed files with 340 additions and 349 deletions

View File

@@ -160,35 +160,18 @@ class TargetManagementTest extends AbstractAccessControllerManagementTest {
READ_TARGET, UPDATE_TARGET + "/type.id==" + targetType1.getId(),
READ_DISTRIBUTION_SET,
CREATE_ROLLOUT, READ_ROLLOUT, HANDLE_ROLLOUT), () -> {
assertThat(targetManagement.findByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(
List.of(1L), "id==*", ds2Type2.getType(), UNPAGED).stream().toList())
.containsExactly(target1Type1);
assertThat(targetManagement.countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable("id==*", List.of(1L), ds2Type2.getType()))
.isEqualTo(1);
final Rollout rollout = testdataFactory.createRolloutByVariables("testRollout", "testDescription", 3, "id==*", ds2Type2, "50", "5");
final List<Long> groups = rolloutGroupManagement.findByRollout(rollout.getId(), UNPAGED).getContent().stream().
map(Identifiable::getId).toList();
assertThat(groups.stream().flatMap(
group -> targetManagement.findByInRolloutGroupWithoutAction(group, UNPAGED).get()).toList())
.containsExactly(target1Type1);
assertThat(groups.stream().flatMap(
group -> rolloutGroupManagement.findTargetsOfRolloutGroup(group, UNPAGED).get()).toList())
.containsExactly(target1Type1);
assertThat(targetManagement.findByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(groups, "id==*", ds2Type2.getType(), UNPAGED))
.isEmpty();
assertThat(targetManagement.countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable("id==*", groups, ds2Type2.getType()))
.isZero();
// as system in context - doesn't apply scopes
final Rollout runAsSystem = systemSecurityContext.runAsSystem(
() -> testdataFactory.createRolloutByVariables(
"testRolloutAsSystem", "testDescriptionAsSystem", 3, "id==*", ds2Type2, "50", "5"));
assertThat(rolloutGroupManagement.findByRollout(runAsSystem.getId(), UNPAGED).getContent().stream()
.flatMap(
group -> targetManagement.findByInRolloutGroupWithoutAction(group.getId(), UNPAGED).getContent().stream()).toList())
.hasSize(3);
});
}

View File

@@ -672,8 +672,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(distributionSets, targets, 34);
enableMultiAssignments();
final List<DistributionSetAssignmentResult> results = deploymentManagement
.assignDistributionSets(deploymentRequests);
final List<DistributionSetAssignmentResult> results = deploymentManagement.assignDistributionSets(deploymentRequests);
assertThat(getResultingActionCount(results)).isEqualTo(deploymentRequests.size());
final List<Long> dsIds = distributionSets.stream().map(DistributionSet::getId).toList();

View File

@@ -38,6 +38,7 @@ import io.github.classgraph.ClassInfo;
import io.github.classgraph.ScanResult;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.PermissionSupport;
import org.eclipse.hawkbit.repository.TenantStatsManagement;
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
@@ -257,7 +258,8 @@ class ManagementSecurityTest extends AbstractJpaIntegrationTest {
assertThat(spelNode.getChild(0) instanceof VariableReference varRef && varRef.toStringAST().equals("#root")).isTrue();
assertThat(spelNode.getChild(1)).isInstanceOf(StringLiteral.class);
final StringLiteral literal = (StringLiteral) spelNode.getChild(1);
preAuthorizedPermissions.add(literal.getLiteralValue().getValue() + "_" + permissionGroup);
preAuthorizedPermissions.add(String.valueOf(literal.getLiteralValue().getValue())
.replace(SpringEvalExpressions.PERMISSION_GROUP_PLACEHOLDER, permissionGroup));
}
default -> throw new IllegalStateException("Unexpected MethodReference: " + method);
}

View File

@@ -10,10 +10,13 @@
package org.eclipse.hawkbit.repository.jpa.management;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.callAs;
import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.withUser;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.SneakyThrows;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -24,8 +27,11 @@ import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
import org.eclipse.hawkbit.security.SecurityContextSerializer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.test.context.TestPropertySource;
@@ -39,6 +45,15 @@ import org.springframework.test.context.TestPropertySource;
@TestPropertySource(properties = { "hawkbit.server.repository.dynamicRolloutsMinInvolvePeriodMS=-1" })
class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
@Configuration
static class Config {
@Bean
SecurityContextSerializer securityContextSerializer() {
return SecurityContextSerializer.JSON_SERIALIZATION;
}
}
@BeforeEach
void reset() {
this.approvalStrategy.setApprovalNeeded(false);
@@ -47,19 +62,21 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
/**
* Verifies a simple rollout flow
*/
@SneakyThrows
@Test
void rolloutFlow() {
final String rolloutName = "rollout-std";
final int amountGroups = 5; // static only
final String targetPrefix = "controller-rollout-std-";
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
final DistributionSet distributionSet = testdataFactory.createDistributionSetLocked("dsFor" + rolloutName);
testdataFactory.createTargets(targetPrefix, 0, amountGroups * 3);
final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30", false, false);
final Rollout rollout = callAs(
withUser("rolloutFlowUser", "READ_DISTRIBUTION_SET", "READ_TARGET", "READ_ROLLOUT", "CREATE_ROLLOUT"),
() -> testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30", false, false));
final List<RolloutGroup> groups = rolloutGroupManagement.findByRollout(
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))
).getContent();
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))).getContent();
// add 2 targets not to be included
testdataFactory.createTargets(targetPrefix, amountGroups * 3, 2);
@@ -89,22 +106,24 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
/**
* Verifies a simple dynamic rollout flow
*/
@SneakyThrows
@Test
void dynamicRolloutFlow() {
final String rolloutName = "dynamic-rollout-std";
final int amountGroups = 2; // static only
final String targetPrefix = "controller-dynamic-rollout-std-";
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
final DistributionSet distributionSet = testdataFactory.createDistributionSetLocked("dsFor" + rolloutName);
testdataFactory.createTargets(targetPrefix, 0, amountGroups * 3);
final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30", false, true);
final Rollout rollout = callAs(
withUser("dynamicRolloutFlow", "READ_DISTRIBUTION_SET", "READ_TARGET", "READ_ROLLOUT", "CREATE_ROLLOUT"),
() -> testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30", false, true));
// rollout is READY
assertRollout(rollout, true, RolloutStatus.READY, amountGroups + 1, amountGroups * 3);
List<RolloutGroup> groups = rolloutGroupManagement.findByRollout(
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))
).getContent();
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))).getContent();
final RolloutGroup dynamic1 = groups.get(amountGroups);
assertRollout(rollout, true, RolloutStatus.READY, amountGroups + 1, amountGroups * 3); // + dynamic
for (int i = 0; i < amountGroups; i++) {
@@ -139,8 +158,7 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
assertRollout(rollout, true, RolloutStatus.RUNNING, amountGroups + 2, amountGroups * 3 + 3);
assertGroup(dynamic1, true, RolloutGroupStatus.RUNNING, 3);
groups = rolloutGroupManagement.findByRollout(
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))
).getContent();
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))).getContent();
final RolloutGroup dynamic2 = groups.get(amountGroups + 1);
assertGroup(dynamic2, true, RolloutGroupStatus.SCHEDULED, 0);
@@ -205,25 +223,27 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
/**
* Verifies a simple dynamic rollout flow with a dynamic group template
*/
@SneakyThrows
@Test
void dynamicRolloutTemplateFlow() {
final String rolloutName = "dynamic-template-rollout-std";
final int amountGroups = 3; // static only
final String targetPrefix = "controller-template-dynamic-rollout-std-";
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
final DistributionSet distributionSet = testdataFactory.createDistributionSetLocked("dsFor" + rolloutName);
// create rollout with amountGroups static groups * 3 targets and dynamic group template with 6 targets
testdataFactory.createTargets(targetPrefix, 0, amountGroups * 3);
final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30",
Action.ActionType.FORCED, 1000, false, true,
RolloutManagement.DynamicRolloutGroupTemplate.builder().nameSuffix("-dyn").targetCount(6).build());
final Rollout rollout = callAs(
withUser("dynamicRolloutTemplateFlow", "READ_DISTRIBUTION_SET", "READ_TARGET", "READ_ROLLOUT", "CREATE_ROLLOUT"),
() -> testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30",
Action.ActionType.FORCED, 1000, false, true,
RolloutManagement.DynamicRolloutGroupTemplate.builder().nameSuffix("-dyn").targetCount(6).build()));
// rollout is READY, amountGroups + 1 (dynamic) rollout groups and amountGroups * 3 targets in static groups
assertRollout(rollout, true, RolloutStatus.READY, amountGroups + 1, amountGroups * 3);
List<RolloutGroup> groups = rolloutGroupManagement.findByRollout(
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))
).getContent();
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))).getContent();
final RolloutGroup dynamic1 = groups.get(amountGroups);
assertRollout(rollout, true, RolloutStatus.READY, amountGroups + 1, amountGroups * 3); // + dynamic
for (int i = 0; i < amountGroups; i++) {
@@ -258,8 +278,7 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
assertRollout(rollout, true, RolloutStatus.RUNNING, amountGroups + 2, amountGroups * 3 + 6);
assertGroup(dynamic1, true, RolloutGroupStatus.RUNNING, 6);
groups = rolloutGroupManagement.findByRollout(
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))
).getContent();
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))).getContent();
final RolloutGroup dynamic2 = groups.get(amountGroups + 1);
assertGroup(dynamic2, true, RolloutGroupStatus.SCHEDULED, 0);
@@ -305,16 +324,19 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
/**
* Verifies a simple pure (no static groups) dynamic rollout flow with a dynamic group template
*/
@SneakyThrows
@Test
void dynamicRolloutPureFlow() {
final String rolloutName = "pure-dynamic-rollout-std";
final String targetPrefix = "controller-pure-dynamic-rollout-std-";
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
final DistributionSet distributionSet = testdataFactory.createDistributionSetLocked("dsFor" + rolloutName);
final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, 0,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30",
Action.ActionType.FORCED, 1000, false, true,
RolloutManagement.DynamicRolloutGroupTemplate.builder().nameSuffix("-dyn").targetCount(6).build());
final Rollout rollout = callAs(
withUser("dynamicRolloutPureFlow", "READ_DISTRIBUTION_SET", "READ_TARGET", "READ_ROLLOUT", "CREATE_ROLLOUT"),
() -> testdataFactory.createRolloutByVariables(rolloutName, rolloutName, 0,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30",
Action.ActionType.FORCED, 1000, false, true,
RolloutManagement.DynamicRolloutGroupTemplate.builder().nameSuffix("-dyn").targetCount(6).build()));
// rollout is READY, amountGroups + 1 (dynamic) rollout groups and amountGroups * 3 targets in static groups
assertRollout(rollout, true, RolloutStatus.READY, 1, 0);
@@ -347,8 +369,7 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
assertRollout(rollout, true, RolloutStatus.RUNNING, 2, 6);
assertGroup(dynamic1, true, RolloutGroupStatus.RUNNING, 6);
groups = rolloutGroupManagement.findByRollout(
rollout.getId(), new OffsetBasedPageRequest(0, 10, Sort.by(Direction.ASC, "id"))
).getContent();
rollout.getId(), new OffsetBasedPageRequest(0, 10, Sort.by(Direction.ASC, "id"))).getContent();
final RolloutGroup dynamic2 = groups.get(1);
assertGroup(dynamic2, true, RolloutGroupStatus.SCHEDULED, 0);
@@ -388,19 +409,21 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
/**
* Verifies a simple rollout flow
*/
@SneakyThrows
@Test
void rollout0ThresholdFlow() {
final String rolloutName = "rollout-std-0threshold";
final int amountGroups = 5; // static only
final String targetPrefix = "controller-rollout-std-0threshold-";
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
final DistributionSet distributionSet = testdataFactory.createDistributionSetLocked("dsFor" + rolloutName);
testdataFactory.createTargets(targetPrefix, 0, amountGroups * 3);
final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "0", "25", false, false);
final Rollout rollout = callAs(
withUser("rollout0ThresholdFlow", "READ_DISTRIBUTION_SET", "READ_TARGET", "READ_ROLLOUT", "CREATE_ROLLOUT"),
() -> testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "0", "25", false, false));
final List<RolloutGroup> groups = rolloutGroupManagement.findByRollout(
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))
).getContent();
rollout.getId(), new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id"))).getContent();
// start rollout
rolloutManagement.start(rollout.getId());

View File

@@ -57,17 +57,14 @@ import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaNamedEntity_;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
@@ -79,7 +76,6 @@ import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification;
/**
@@ -729,60 +725,6 @@ class TargetManagementTest extends AbstractRepositoryManagementWithMetadataTest<
"notExisting", ds.getId(), "name==*")).isFalse();
}
/**
* Tests action based aspects of the dynamic group assignment filters.
* Target matches filter no active action with ge weight.
*/
@Test
void findByTargetFilterQueryAndNoOverridingActionsAndNotInRolloutAndCompatibleAndUpdatable() {
final String targetPrefix = "dyn_action_filter_";
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
final List<Target> targets = testdataFactory.createTargets(targetPrefix, 10);
final Rollout rolloutOlder = testdataFactory.createRollout();
final Rollout rollout = testdataFactory.createRollout();
final Rollout rolloutNewer = testdataFactory.createRollout();
int target = 0;
final List<Integer> expected = new ArrayList<>();
// old ro with less weight - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 0, Status.RUNNING, distributionSet);
// old ro with equal weight - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 10, Status.RUNNING, distributionSet);
// old ro with bigger weight, scheduled - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 11, Status.SCHEDULED, distributionSet);
// old ro with bigger weight, running - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 11, Status.RUNNING, distributionSet);
// old ro with bigger weight, running - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 11, Status.FINISHED, distributionSet);
// same ro - doesn't match
createAction(targets.get(target++), rollout, 10, Status.RUNNING, distributionSet);
// new ro with less weight - doesn't match
createAction(targets.get(target++), rolloutNewer, 0, Status.RUNNING, distributionSet);
// new ro with less weight - doesn't match
createAction(targets.get(target++), rolloutNewer, 5, Status.WARNING, distributionSet);
// NEW ro with EQUAL weight - doesn't match
createAction(targets.get(target++), rolloutNewer, 10, Status.RUNNING, distributionSet);
// new ro with BIGGER weight - doesn't match
createAction(targets.get(target), rolloutNewer, 20, Status.DOWNLOADED, distributionSet);
final Slice<Target> matching =
targetManagement.findByRsqlAndNoOverridingActionsAndNotInRolloutAndCompatibleAndUpdatable(
rollout.getId(), "controllerid==dyn_action_filter_*", distributionSet.getType(), PAGE);
assertThat(matching.getNumberOfElements()).isEqualTo(expected.size());
assertThat(matching.stream()
.map(Target::getControllerId)
.map(s -> s.substring(targetPrefix.length()))
.map(Integer::parseInt)
.sorted()
.toList()).isEqualTo(expected);
}
/**
* Target matches filter for not existing DS.
*/
@@ -834,7 +776,6 @@ class TargetManagementTest extends AbstractRepositoryManagementWithMetadataTest<
verifyThrownExceptionBy(
() -> targetManagement.findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(NOT_EXIST_IDL, "name==*", PAGE),
"DistributionSet");
verifyThrownExceptionBy(() -> targetManagement.findByInRolloutGroupWithoutAction(NOT_EXIST_IDL, PAGE), "RolloutGroup");
verifyThrownExceptionBy(() -> targetManagement.findByAssignedDistributionSet(NOT_EXIST_IDL, PAGE), "DistributionSet");
verifyThrownExceptionBy(
() -> targetManagement.findByAssignedDistributionSetAndRsql(NOT_EXIST_IDL, "name==*", PAGE), "DistributionSet");
@@ -1124,24 +1065,6 @@ class TargetManagementTest extends AbstractRepositoryManagementWithMetadataTest<
}
}
private void createAction(final Target target, final Rollout rollout, final Integer weight, final Action.Status status,
final DistributionSet distributionSet) {
final JpaAction action = new JpaAction();
action.setActionType(Action.ActionType.FORCED);
action.setTarget(target);
action.setInitiatedBy("test");
if (rollout != null) {
action.setRollout(rollout);
}
if (weight != null) {
action.setWeight(weight);
}
action.setStatus(status);
action.setActive(status != Status.FINISHED && status != Status.ERROR && status != Status.CANCELED);
action.setDistributionSet(distributionSet);
actionRepository.save(action);
}
private void validateFoundTargetsByRsql(final String rsqlFilter, final String... controllerIds) {
final Page<? extends Target> foundTargetsByMetadataAndControllerId = targetManagement.findByRsql(rsqlFilter, PAGE);
final long foundTargetsByMetadataAndControllerIdCount = targetManagement.countByRsql(rsqlFilter);

View File

@@ -50,7 +50,7 @@ import org.springframework.data.domain.Slice;
* Story: Auto assign checker
*/
@SuppressWarnings("java:S6813") // constructor injects are not possible for test classes
class JpaAutoAssignExecutorIntTest extends AbstractJpaIntegrationTest {
class AutoAssignExecutorIntTest extends AbstractJpaIntegrationTest {
private static final String SPACE_AND_DESCRIPTION = " description";

View File

@@ -45,7 +45,7 @@ import org.springframework.transaction.PlatformTransactionManager;
* Story: Auto assign checker
*/
@ExtendWith(MockitoExtension.class)
class JpaAutoAssignExecutorTest {
class AutoAssignExecutorTest {
@Mock
private TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement;

View File

@@ -0,0 +1,103 @@
/**
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.scheduler;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Slice;
public class RolloutExecutorTest extends AbstractJpaIntegrationTest {
@Autowired
private JpaRolloutExecutor jpaRolloutExecutor;
/**
* Tests action based aspects of the dynamic group assignment filters.
* Target matches filter no active action with ge weight.
*/
@Test
void findByTargetFilterQueryAndNoOverridingActionsAndNotInRolloutAndCompatibleAndUpdatable() {
final String targetPrefix = "dyn_action_filter_";
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
final List<Target> targets = testdataFactory.createTargets(targetPrefix, 10);
final Rollout rolloutOlder = testdataFactory.createRollout();
final Rollout rollout = testdataFactory.createRollout();
final Rollout rolloutNewer = testdataFactory.createRollout();
int target = 0;
final List<Integer> expected = new ArrayList<>();
// old ro with less weight - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 0, Action.Status.RUNNING, distributionSet);
// old ro with equal weight - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 10, Action.Status.RUNNING, distributionSet);
// old ro with bigger weight, scheduled - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 11, Action.Status.SCHEDULED, distributionSet);
// old ro with bigger weight, running - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 11, Action.Status.RUNNING, distributionSet);
// old ro with bigger weight, running - match
expected.add(target);
createAction(targets.get(target++), rolloutOlder, 11, Action.Status.FINISHED, distributionSet);
// same ro - doesn't match
createAction(targets.get(target++), rollout, 10, Action.Status.RUNNING, distributionSet);
// new ro with less weight - doesn't match
createAction(targets.get(target++), rolloutNewer, 0, Action.Status.RUNNING, distributionSet);
// new ro with less weight - doesn't match
createAction(targets.get(target++), rolloutNewer, 5, Action.Status.WARNING, distributionSet);
// NEW ro with EQUAL weight - doesn't match
createAction(targets.get(target++), rolloutNewer, 10, Action.Status.RUNNING, distributionSet);
// new ro with BIGGER weight - doesn't match
createAction(targets.get(target), rolloutNewer, 20, Action.Status.DOWNLOADED, distributionSet);
final Slice<Target> matching =
jpaRolloutExecutor.findByRsqlAndNoOverridingActionsAndNotInRolloutAndCompatibleAndUpdatable(
rollout.getId(), "controllerid==dyn_action_filter_*", distributionSet.getType(), PAGE);
assertThat(matching.getNumberOfElements()).isEqualTo(expected.size());
assertThat(matching.stream()
.map(Target::getControllerId)
.map(s -> s.substring(targetPrefix.length()))
.map(Integer::parseInt)
.sorted()
.toList()).isEqualTo(expected);
}
private void createAction(
final Target target, final Rollout rollout, final Integer weight, final Action.Status status, final DistributionSet distributionSet) {
final JpaAction action = new JpaAction();
action.setActionType(Action.ActionType.FORCED);
action.setTarget(target);
action.setInitiatedBy("test");
if (rollout != null) {
action.setRollout(rollout);
}
if (weight != null) {
action.setWeight(weight);
}
action.setStatus(status);
action.setActive(status != Action.Status.FINISHED && status != Action.Status.ERROR && status != Action.Status.CANCELED);
action.setDistributionSet(distributionSet);
actionRepository.save(action);
}
}