Prioritisation of assignments via mgmt-API (#895)

* Updating the schema for targetfilterquery and rollout
* Updating the weight validation logic and tests
* Make weight optional
* Fix existing multi assignment tests by adding weight, remove weight from TargetFilterQuery
* Add weight validation tests, fix tests
* Add mgmt api tests for assignment and getting action with weight
* Add management layer validation and tests for creating rollouts with weight
* Fix amqp test, add repo level validation to resource tests
* Add weight to rollout mgmt-api and tests
* Add weight to mgmt api target Filter create and update
* Add target filter auto assign weight. disable enforcement of setting a weight in multiassign mode
* Remove ignored tests, fix api doc
* Fix minor findings
* Fix findings
* Remove hardcoded min weight
* Add docu text, fix findings
* Fix api documentation
* Expose weight via DMF
* Expose actions according to weight via ddi
* Fix documentation
* Add method to get actions ordered by weight to deploymentManagement
* Updating the schema for targetfilterquery and rollout
* Updated the indentation
* Updated the helper class, fixed the randomUID in test factory
* Updated the class name with prefix JPA
* Adding the missing License for WeightValidationHelper class
* Adding documentation to the dmf api on weight
* Removed the merger markers
* Updated the class name
* Removed the redundant method
* Addressed final PR comments
* Updated the missing testcase with latest default weight value
* Reverting the default value of weight back to 1000 and updated tests

Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>
This commit is contained in:
Stefan Klotz
2019-11-08 10:47:35 +01:00
committed by Stefan Behl
parent 09f2d8a481
commit 9cb5d31396
98 changed files with 2425 additions and 875 deletions

View File

@@ -212,6 +212,7 @@ public abstract class AbstractDsAssignmentStrategy {
final JpaAction actionForTarget = new JpaAction();
actionForTarget.setActionType(targetWithActionType.getActionType());
actionForTarget.setForcedTime(targetWithActionType.getForceTime());
actionForTarget.setWeight(targetWithActionType.getWeight());
actionForTarget.setActive(true);
actionForTarget.setTarget(target);
actionForTarget.setDistributionSet(set);

View File

@@ -28,7 +28,6 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -101,20 +100,33 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
List<Action> findByTargetAndActiveOrderByIdAsc(JpaTarget target, boolean active);
/**
* Retrieves the oldest {@link Action} that is active and referring to the
* given {@link Target}.
*
* @param sort
* order
* Retrieves the active {@link Action}s with the highest weights that refer
* to the given {@link Target}. If {@link Action}s have the same weight they
* are ordered ascending by ID (oldest ones first).
*
* @param pageable
* pageable
* @param controllerId
* the target to find assigned actions
* @param active
* the action active flag
*
* @return the found {@link Action}
* @return the found {@link Action}s
*/
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
Optional<Action> findFirstByTargetControllerIdAndActive(Sort sort, String controllerId, boolean active);
Page<Action> findByTargetControllerIdAndActiveIsTrueAndWeightIsNotNullOrderByWeightDescIdAsc(Pageable pageable,
String controllerId);
/**
* Retrieves the active {@link Action}s with the lowest IDs (the oldest one)
* whose weight is null and that that refers to the given {@link Target}.
*
* @param pageable
* pageable
* @param controllerId
* the target to find assigned actions
* @return the found {@link Action}s
*/
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
Page<Action> findByTargetControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(Pageable pageable,
String controllerId);
/**
* Checks if an active action exists for given

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.model.Action;
import org.springframework.data.domain.PageRequest;
/**
* Implements utility methods for managing {@link Action}s
*/
public class JpaActionManagement {
protected final ActionRepository actionRepository;
protected final RepositoryProperties repositoryProperties;
protected JpaActionManagement(final ActionRepository actionRepository,
final RepositoryProperties repositoryProperties) {
this.actionRepository = actionRepository;
this.repositoryProperties = repositoryProperties;
}
protected List<Action> findActiveActionsWithHighestWeightConsideringDefault(final String controllerId,
final int maxActionCount) {
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
return Collections.emptyList();
}
final List<Action> actions = new ArrayList<>();
final PageRequest pageable = PageRequest.of(0, maxActionCount);
actions.addAll(actionRepository
.findByTargetControllerIdAndActiveIsTrueAndWeightIsNotNullOrderByWeightDescIdAsc(pageable, controllerId)
.getContent());
actions.addAll(actionRepository
.findByTargetControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(pageable, controllerId)
.getContent());
final Comparator<Action> actionImportance = Comparator.comparingInt(this::getWeightConsideringDefault)
.reversed().thenComparing(Action::getId);
return actions.stream().sorted(actionImportance).limit(maxActionCount).collect(Collectors.toList());
}
protected int getWeightConsideringDefault(final Action action) {
return action.getWeight().orElse(repositoryProperties.getActionWeightIfAbsent());
}
}

View File

@@ -110,7 +110,7 @@ import com.google.common.collect.Sets;
*/
@Transactional(readOnly = true)
@Validated
public class JpaControllerManagement implements ControllerManagement {
public class JpaControllerManagement extends JpaActionManagement implements ControllerManagement {
private static final Logger LOG = LoggerFactory.getLogger(JpaControllerManagement.class);
private final BlockingDeque<TargetPoll> queue;
@@ -118,9 +118,6 @@ public class JpaControllerManagement implements ControllerManagement {
@Autowired
private EntityManager entityManager;
@Autowired
private ActionRepository actionRepository;
@Autowired
private TargetRepository targetRepository;
@@ -157,10 +154,9 @@ public class JpaControllerManagement implements ControllerManagement {
@Autowired
private TenantAware tenantAware;
private final RepositoryProperties repositoryProperties;
JpaControllerManagement(final ScheduledExecutorService executorService,
final RepositoryProperties repositoryProperties) {
final RepositoryProperties repositoryProperties, final ActionRepository actionRepository) {
super(actionRepository, repositoryProperties);
if (!repositoryProperties.isEagerPollPersistence()) {
executorService.scheduleWithFixedDelay(this::flushUpdateQueue,
@@ -171,8 +167,6 @@ public class JpaControllerManagement implements ControllerManagement {
} else {
queue = null;
}
this.repositoryProperties = repositoryProperties;
}
@Override
@@ -346,23 +340,19 @@ public class JpaControllerManagement implements ControllerManagement {
}
@Override
public Optional<Action> findOldestActiveActionByTarget(final String controllerId) {
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
return Optional.empty();
}
// used in favorite to findFirstByTargetAndActiveOrderByIdAsc due to
// DATAJPA-841 issue.
return actionRepository.findFirstByTargetControllerIdAndActive(new Sort(Direction.ASC, "id"), controllerId,
true);
public Optional<Action> findActiveActionWithHighestWeight(final String controllerId) {
return findActiveActionsWithHighestWeight(controllerId, 1).stream().findFirst();
}
@Override
public Page<Action> findActiveActionsByTarget(final Pageable pageable, final String controllerId) {
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
return Page.empty();
}
return actionRepository.findByActiveAndTarget(pageable, controllerId, true);
public List<Action> findActiveActionsWithHighestWeight(final String controllerId,
final int maxActionCount) {
return findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
}
@Override
public int getWeightConsideringDefault(final Action action) {
return super.getWeightConsideringDefault(action);
}
@Override
@@ -376,7 +366,7 @@ public class JpaControllerManagement implements ControllerManagement {
}
@Override
public void deleteExistingTarget(@NotEmpty String controllerId) {
public void deleteExistingTarget(@NotEmpty final String controllerId) {
final Target target = targetRepository.findByControllerId(controllerId)
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
targetRepository.deleteById(target.getId());

View File

@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit.repository.jpa;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED;
import java.io.Serializable;
@@ -38,6 +37,7 @@ import org.eclipse.hawkbit.repository.ActionFields;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
@@ -57,6 +57,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper;
import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -103,7 +105,7 @@ import com.google.common.collect.Lists;
*/
@Transactional(readOnly = true)
@Validated
public class JpaDeploymentManagement implements DeploymentManagement {
public class JpaDeploymentManagement extends JpaActionManagement implements DeploymentManagement {
private static final Logger LOG = LoggerFactory.getLogger(JpaDeploymentManagement.class);
@@ -124,7 +126,6 @@ public class JpaDeploymentManagement implements DeploymentManagement {
}
private final EntityManager entityManager;
private final ActionRepository actionRepository;
private final DistributionSetRepository distributionSetRepository;
private final TargetRepository targetRepository;
private final ActionStatusRepository actionStatusRepository;
@@ -146,9 +147,10 @@ public class JpaDeploymentManagement implements DeploymentManagement {
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final Database database) {
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final Database database,
final RepositoryProperties repositoryProperties) {
super(actionRepository, repositoryProperties);
this.entityManager = entityManager;
this.actionRepository = actionRepository;
this.distributionSetRepository = distributionSetRepository;
this.targetRepository = targetRepository;
this.actionStatusRepository = actionStatusRepository;
@@ -194,6 +196,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
@Transactional(isolation = Isolation.READ_COMMITTED)
public List<DistributionSetAssignmentResult> assignDistributionSets(
final List<DeploymentRequest> deploymentRequests, final String actionMessage) {
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
.validate(deploymentRequests);
return assignDistributionSets(deploymentRequests, actionMessage, onlineDsAssignmentStrategy);
}
@@ -275,8 +279,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
final AbstractDsAssignmentStrategy assignmentStrategy) {
final JpaDistributionSet distributionSetEntity = getAndValidateDsById(dsID);
final List<String> targetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId).distinct()
.collect(Collectors.toList());
final List<String> targetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId)
.distinct().collect(Collectors.toList());
final List<JpaTarget> targetEntities = assignmentStrategy.findTargetsForAssignment(targetIds,
distributionSetEntity.getId());
@@ -285,8 +289,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
return allTargetsAlreadyAssignedResult(distributionSetEntity, targetsWithActionType.size());
}
final List<JpaAction> assignedActions = doAssignDistributionSetToTargets(targetsWithActionType,
actionMessage, assignmentStrategy, distributionSetEntity, targetEntities);
final List<JpaAction> assignedActions = doAssignDistributionSetToTargets(targetsWithActionType, actionMessage,
assignmentStrategy, distributionSetEntity, targetEntities);
return buildAssignmentResult(distributionSetEntity, assignedActions, targetsWithActionType.size());
}
@@ -659,6 +663,16 @@ public class JpaDeploymentManagement implements DeploymentManagement {
return actionRepository.findByActiveAndTarget(pageable, controllerId, false);
}
@Override
public List<Action> findActiveActionsWithHighestWeight(final String controllerId, final int maxActionCount) {
return findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
}
@Override
public int getWeightConsideringDefault(final Action action) {
return super.getWeightConsideringDefault(action);
}
@Override
public long countActionsByTarget(final String controllerId) {
throwExceptionIfTargetDoesNotExist(controllerId);
@@ -823,7 +837,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
}
private boolean isMultiAssignmentsEnabled() {
return getConfigValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class);
return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
.isMultiAssignmentsEnabled();
}
private <T extends Serializable> T getConfigValue(final String key, final Class<T> valueType) {

View File

@@ -34,6 +34,7 @@ import org.eclipse.hawkbit.repository.RolloutHelper;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.RolloutStatusCache;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.builder.GenericRolloutUpdate;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
@@ -43,6 +44,8 @@ import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEve
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
import org.eclipse.hawkbit.repository.exception.NoWeightProvidedInMultiAssignmentModeException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
@@ -57,6 +60,8 @@ import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification;
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper;
import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -74,6 +79,7 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -165,9 +171,12 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
final DistributionSetManagement distributionSetManagement, final ApplicationContext context,
final EventPublisherHolder eventPublisherHolder, final VirtualPropertyReplacer virtualPropertyReplacer,
final PlatformTransactionManager txManager, final TenantAware tenantAware, final LockRegistry lockRegistry,
final Database database, final RolloutApprovalStrategy rolloutApprovalStrategy) {
final Database database, final RolloutApprovalStrategy rolloutApprovalStrategy,
final TenantConfigurationManagement tenantConfigurationManagement,
final SystemSecurityContext systemSecurityContext) {
super(targetManagement, deploymentManagement, rolloutGroupManagement, distributionSetManagement, context,
virtualPropertyReplacer, txManager, tenantAware, lockRegistry, rolloutApprovalStrategy);
virtualPropertyReplacer, txManager, tenantAware, lockRegistry, rolloutApprovalStrategy,
tenantConfigurationManagement, systemSecurityContext);
this.eventPublisherHolder = eventPublisherHolder;
this.database = database;
}
@@ -226,7 +235,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
}
private JpaRollout createRollout(final JpaRollout rollout) {
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(rollout);
final Long totalTargets = targetManagement.countByRsql(rollout.getTargetFilterQuery());
if (totalTargets == 0) {
throw new ValidationException("Rollout does not match any existing targets");
@@ -618,6 +627,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
action.setStatus(Status.SCHEDULED);
action.setRollout(rollout);
action.setRolloutGroup(rolloutGroup);
rollout.getWeight().ifPresent(action::setWeight);
actionRepository.save(action);
});
}
@@ -1008,6 +1018,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
update.getDescription().ifPresent(rollout::setDescription);
update.getActionType().ifPresent(rollout::setActionType);
update.getForcedTime().ifPresent(rollout::setForcedTime);
update.getWeight().ifPresent(rollout::setWeight);
update.getStartAt().ifPresent(rollout::setStartAt);
update.getSet().ifPresent(setId -> {
final DistributionSet set = distributionSetManagement.get(setId)
@@ -1136,5 +1147,4 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
QuotaHelper.assertAssignmentQuota(target.getId(), requested, quota, Action.class, Target.class,
actionRepository::countByTargetId);
}
}

View File

@@ -18,6 +18,8 @@ import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
import org.eclipse.hawkbit.repository.builder.GenericTargetFilterQueryUpdate;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryUpdate;
@@ -32,11 +34,14 @@ import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper;
import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
@@ -67,19 +72,24 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
private final DistributionSetManagement distributionSetManagement;
private final QuotaManagement quotaManagement;
private final TenantConfigurationManagement tenantConfigurationManagement;
private final SystemSecurityContext systemSecurityContext;
private final Database database;
JpaTargetFilterQueryManagement(final TargetFilterQueryRepository targetFilterQueryRepository,
final TargetRepository targetRepository, final VirtualPropertyReplacer virtualPropertyReplacer,
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
final Database database) {
final Database database, final TenantConfigurationManagement tenantConfigurationManagement,
final SystemSecurityContext systemSecurityContext) {
this.targetFilterQueryRepository = targetFilterQueryRepository;
this.targetRepository = targetRepository;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.distributionSetManagement = distributionSetManagement;
this.quotaManagement = quotaManagement;
this.database = database;
this.tenantConfigurationManagement = tenantConfigurationManagement;
this.systemSecurityContext = systemSecurityContext;
}
@Override
@@ -92,6 +102,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
// enforce the 'max targets per auto assign' quota right here even if
// the result of the filter query can vary over time
if (create.getAutoAssignDistributionSetId().isPresent()) {
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(create);
create.getQuery().ifPresent(this::assertMaxTargetsQuota);
}
@@ -222,30 +233,26 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
@Override
@Transactional
public TargetFilterQuery updateAutoAssignDSWithActionType(final long queryId, final Long dsId,
final ActionType actionType) {
final JpaTargetFilterQuery targetFilterQuery = findTargetFilterQueryOrThrowExceptionIfNotFound(queryId);
if (dsId == null) {
public TargetFilterQuery updateAutoAssignDS(final AutoAssignDistributionSetUpdate update) {
final JpaTargetFilterQuery targetFilterQuery = findTargetFilterQueryOrThrowExceptionIfNotFound(
update.getTargetFilterId());
if (update.getDsId() == null) {
targetFilterQuery.setAutoAssignDistributionSet(null);
targetFilterQuery.setAutoAssignActionType(null);
targetFilterQuery.setAutoAssignWeight(null);
} else {
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(update);
// we cannot be sure that the quota was enforced at creation time
// because the Target Filter Query REST API does not allow to
// specify an
// auto-assign distribution set when creating a target filter query
assertMaxTargetsQuota(targetFilterQuery.getQuery());
final JpaDistributionSet distributionSetToAutoAssign = findDistributionSetAndThrowExceptionIfNotFound(dsId);
// must be completed and not soft deleted
verifyDistributionSetAndThrowExceptionIfNotValid(distributionSetToAutoAssign);
targetFilterQuery.setAutoAssignDistributionSet(distributionSetToAutoAssign);
// the action type is set to FORCED per default (when not explicitly
// specified)
targetFilterQuery.setAutoAssignActionType(sanitizeAutoAssignActionType(actionType));
final JpaDistributionSet ds = findDistributionSetAndThrowExceptionIfNotFound(update.getDsId());
verifyDistributionSetAndThrowExceptionIfNotValid(ds);
targetFilterQuery.setAutoAssignDistributionSet(ds);
targetFilterQuery.setAutoAssignActionType(sanitizeAutoAssignActionType(update.getActionType()));
targetFilterQuery.setAutoAssignWeight(update.getWeight());
}
return targetFilterQueryRepository.save(targetFilterQuery);
}
@@ -288,5 +295,4 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
targetRepository.count(RSQLUtility.parse(query, TargetFields.class, virtualPropertyReplacer, database)),
quotaManagement.getMaxTargetsPerAutoAssignment(), Target.class, TargetFilterQuery.class);
}
}

View File

@@ -541,9 +541,11 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetRepository targetRepository,
final VirtualPropertyReplacer virtualPropertyReplacer,
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
final JpaProperties properties) {
final JpaProperties properties, final TenantConfigurationManagement tenantConfigurationManagement,
final SystemSecurityContext systemSecurityContext) {
return new JpaTargetFilterQueryManagement(targetFilterQueryRepository, targetRepository,
virtualPropertyReplacer, distributionSetManagement, quotaManagement, properties.getDatabase());
virtualPropertyReplacer, distributionSetManagement, quotaManagement, properties.getDatabase(),
tenantConfigurationManagement, systemSecurityContext);
}
/**
@@ -620,10 +622,13 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
final DistributionSetManagement distributionSetManagement, final ApplicationContext context,
final EventPublisherHolder eventPublisherHolder, final VirtualPropertyReplacer virtualPropertyReplacer,
final PlatformTransactionManager txManager, final TenantAware tenantAware, final LockRegistry lockRegistry,
final JpaProperties properties, final RolloutApprovalStrategy rolloutApprovalStrategy) {
final JpaProperties properties, final RolloutApprovalStrategy rolloutApprovalStrategy,
final TenantConfigurationManagement tenantConfigurationManagement,
final SystemSecurityContext systemSecurityContext) {
return new JpaRolloutManagement(targetManagement, deploymentManagement, rolloutGroupManagement,
distributionSetManagement, context, eventPublisherHolder, virtualPropertyReplacer, txManager,
tenantAware, lockRegistry, properties.getDatabase(), rolloutApprovalStrategy);
tenantAware, lockRegistry, properties.getDatabase(), rolloutApprovalStrategy,
tenantConfigurationManagement, systemSecurityContext);
}
/**
@@ -671,11 +676,11 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
final PlatformTransactionManager txManager,
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware,
final JpaProperties properties) {
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetRepository, targetRepository,
actionStatusRepository, auditorProvider, eventPublisherHolder, afterCommit, virtualPropertyReplacer,
txManager, tenantConfigurationManagement, quotaManagement, systemSecurityContext, tenantAware,
properties.getDatabase());
properties.getDatabase(), repositoryProperties);
}
/**
@@ -686,8 +691,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
@Bean
@ConditionalOnMissingBean
ControllerManagement controllerManagement(final ScheduledExecutorService executorService,
final RepositoryProperties repositoryProperties) {
return new JpaControllerManagement(executorService, repositoryProperties);
final RepositoryProperties repositoryProperties, final ActionRepository actionRepository) {
return new JpaControllerManagement(executorService, repositoryProperties, actionRepository);
}
@Bean

View File

@@ -97,6 +97,8 @@ public class AutoAssignChecker {
final Page<TargetFilterQuery> filterQueries = targetFilterQueryManagement.findWithAutoAssignDS(pageRequest);
// we should ensure that the filter queries are executed
// in the order of weights
for (final TargetFilterQuery filterQuery : filterQueries) {
checkByTargetFilterQueryAndAssignDS(filterQuery);
}
@@ -143,7 +145,8 @@ public class AutoAssignChecker {
return DeploymentHelper.runInNewTransaction(transactionManager, "autoAssignDSToTargets",
Isolation.READ_COMMITTED.value(), status -> {
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(
targetFilterQuery.getQuery(), dsId, targetFilterQuery.getAutoAssignActionType(), PAGE_SIZE);
targetFilterQuery.getQuery(), dsId, targetFilterQuery.getAutoAssignActionType(),
targetFilterQuery.getAutoAssignWeight().orElse(null), PAGE_SIZE);
final int count = deploymentRequests.size();
if (count > 0) {
deploymentManagement.assignDistributionSets(deploymentRequests, actionMessage);
@@ -168,17 +171,15 @@ public class AutoAssignChecker {
* @return list of targets with action type
*/
private List<DeploymentRequest> createAssignmentRequests(final String targetFilterQuery, final Long dsId,
final ActionType type, final int count) {
final ActionType type, final Integer weight, final int count) {
final Page<Target> targets = targetManagement.findByTargetFilterQueryAndNonDS(PageRequest.of(0, count), dsId,
targetFilterQuery);
// the action type is set to FORCED per default (when not explicitly
// specified)
final ActionType autoAssignActionType = type == null ? ActionType.FORCED : type;
return targets.getContent().stream()
.map(t -> DeploymentManagement.deploymentRequest(t.getControllerId(), dsId)
.setActionType(autoAssignActionType).build())
.collect(Collectors.toList());
return targets.getContent().stream().map(t -> DeploymentManagement.deploymentRequest(t.getControllerId(), dsId)
.setActionType(autoAssignActionType).setWeight(weight).build()).collect(Collectors.toList());
}
}

View File

@@ -31,6 +31,7 @@ public class JpaRolloutCreate extends AbstractRolloutUpdateCreate<RolloutCreate>
rollout.setDistributionSet(findDistributionSetAndThrowExceptionIfNotFound(set));
rollout.setTargetFilterQuery(targetFilterQuery);
rollout.setStartAt(startAt);
rollout.setWeight(weight);
if (actionType != null) {
rollout.setActionType(actionType);

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.repository.jpa.builder;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
import org.eclipse.hawkbit.repository.builder.GenericTargetFilterQueryUpdate;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
@@ -36,4 +37,9 @@ public class JpaTargetFilterQueryBuilder implements TargetFilterQueryBuilder {
return new JpaTargetFilterQueryCreate(distributionSetManagement);
}
@Override
public AutoAssignDistributionSetUpdate updateAutoAssign(final long id) {
return new AutoAssignDistributionSetUpdate(id);
}
}

View File

@@ -36,7 +36,8 @@ public class JpaTargetFilterQueryCreate extends AbstractTargetFilterQueryUpdateC
return new JpaTargetFilterQuery(name, query,
getAutoAssignDistributionSetId().map(this::findDistributionSetAndThrowExceptionIfNotFound).orElse(null),
getAutoAssignActionType().filter(JpaTargetFilterQueryCreate::isAutoAssignActionTypeValid).orElse(null));
getAutoAssignActionType().filter(JpaTargetFilterQueryCreate::isAutoAssignActionTypeValid).orElse(null),
weight);
}
private DistributionSet findDistributionSetAndThrowExceptionIfNotFound(final Long setId) {

View File

@@ -28,6 +28,8 @@ import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedSubgraph;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
@@ -89,6 +91,11 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Column(name = "forced_time")
private long forcedTime;
@Column(name = "weight")
@Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX)
private Integer weight;
@Column(name = "status", nullable = false)
@ObjectTypeConverter(name = "status", objectType = Action.Status.class, dataType = Integer.class, conversionValues = {
@ConversionValue(objectValue = "FINISHED", dataValue = "0"),
@@ -126,7 +133,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Column(name = "maintenance_time_zone", updatable = false, length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH)
private String maintenanceWindowTimeZone;
@Column(name = "external_ref", length = Action.EXTERNAL_REF_MAX_LENGTH)
private String externalRef;
@@ -192,6 +199,15 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
this.forcedTime = forcedTime;
}
@Override
public Optional<Integer> getWeight() {
return Optional.ofNullable(weight);
}
public void setWeight(final Integer weight) {
this.weight = weight;
}
@Override
public RolloutGroup getRolloutGroup() {
return rolloutGroup;
@@ -213,8 +229,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Override
public String toString() {
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id="
+ getId() + ", actionType=" + getActionType() + ", isActive=" + isActive() + ", createdAt="
+ getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + "]";
+ getId() + ", actionType=" + getActionType() + ", weight=" + getWeight() + ", isActive=" + isActive()
+ ", createdAt=" + getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + "]";
}
@Override
@@ -337,7 +353,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
}
@Override
public void setExternalRef(String externalRef) {
public void setExternalRef(final String externalRef) {
this.externalRef = externalRef;
}

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.model;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.persistence.Column;
@@ -23,6 +24,8 @@ import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@@ -90,7 +93,7 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
@ConversionValue(objectValue = "DELETING", dataValue = "9"),
@ConversionValue(objectValue = "DELETED", dataValue = "10"),
@ConversionValue(objectValue = "WAITING_FOR_APPROVAL", dataValue = "11"),
@ConversionValue(objectValue = "APPROVAL_DENIED", dataValue = "12")})
@ConversionValue(objectValue = "APPROVAL_DENIED", dataValue = "12") })
@Convert("rolloutstatus")
@NotNull
private RolloutStatus status = RolloutStatus.CREATING;
@@ -131,6 +134,11 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
@Size(max = Rollout.APPROVAL_REMARK_MAX_SIZE)
private String approvalRemark;
@Column(name = "weight")
@Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX)
private Integer weight;
@Transient
private transient TotalTargetCountStatus totalTargetCountStatus;
@@ -204,6 +212,15 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
this.forcedTime = forcedTime;
}
@Override
public Optional<Integer> getWeight() {
return Optional.ofNullable(weight);
}
public void setWeight(final Integer weight) {
this.weight = weight;
}
@Override
public long getTotalTargets() {
return totalTargets;
@@ -299,5 +316,4 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
public void setApprovalRemark(final String approvalRemark) {
this.approvalRemark = approvalRemark;
}
}

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.Optional;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
@@ -66,11 +68,15 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
@ObjectTypeConverter(name = "autoAssignActionType", objectType = Action.ActionType.class, dataType = Integer.class, conversionValues = {
@ConversionValue(objectValue = "FORCED", dataValue = "0"),
@ConversionValue(objectValue = "SOFT", dataValue = "1"),
// Conversion for 'TIMEFORCED' is disabled because it is not permitted in autoAssignment
@ConversionValue(objectValue = "DOWNLOAD_ONLY", dataValue = "3")})
// Conversion for 'TIMEFORCED' is disabled because it is not
// permitted in autoAssignment
@ConversionValue(objectValue = "DOWNLOAD_ONLY", dataValue = "3") })
@Convert("autoAssignActionType")
private ActionType autoAssignActionType;
@Column(name = "auto_assign_weight", nullable = true)
private Integer autoAssignWeight;
public JpaTargetFilterQuery() {
// Default constructor for JPA.
}
@@ -86,13 +92,16 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
* of the {@link TargetFilterQuery}.
* @param autoAssignActionType
* of the {@link TargetFilterQuery}.
* @param autoAssignWeight
* of the {@link TargetFilterQuery}.
*/
public JpaTargetFilterQuery(final String name, final String query, final DistributionSet autoAssignDistributionSet,
final ActionType autoAssignActionType) {
final ActionType autoAssignActionType, final Integer autoAssignWeight) {
this.name = name;
this.query = query;
this.autoAssignDistributionSet = (JpaDistributionSet) autoAssignDistributionSet;
this.autoAssignActionType = autoAssignActionType;
this.autoAssignWeight = autoAssignWeight;
}
@Override
@@ -131,6 +140,15 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
this.autoAssignActionType = actionType;
}
@Override
public Optional<Integer> getAutoAssignWeight() {
return Optional.ofNullable(autoAssignWeight);
}
public void setAutoAssignWeight(final Integer weight) {
this.autoAssignWeight = weight;
}
@Override
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.utils;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.security.SystemSecurityContext;
/**
* A collection of static helper methods for the tenant configuration
*/
public final class TenantConfigHelper {
private final TenantConfigurationManagement tenantConfigurationManagement;
private final SystemSecurityContext systemSecurityContext;
private TenantConfigHelper(final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.systemSecurityContext = systemSecurityContext;
this.tenantConfigurationManagement = tenantConfigurationManagement;
}
/**
* Setting the context of the tenant.
*
* @param systemSecurityContext
* Security context used to get the tenant and for execution
* @param tenantConfigurationManagement
* to get the value from
* @return is active
*/
public static TenantConfigHelper usingContext(final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
return new TenantConfigHelper(systemSecurityContext, tenantConfigurationManagement);
}
/**
* Is multi-assignments enabled for the current tenant
*
* @return is active
*/
public boolean isMultiAssignmentsEnabled() {
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
.getConfigurationValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class).getValue());
}
}

View File

@@ -0,0 +1,132 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.utils;
import java.util.List;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
import org.eclipse.hawkbit.repository.exception.NoWeightProvidedInMultiAssignmentModeException;
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetFilterQueryCreate;
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.security.SystemSecurityContext;
/**
* Utility class to handle weight validation in Rollout, Auto Assignments, and
* Online Assignment.
*/
public final class WeightValidationHelper {
private final TenantConfigurationManagement tenantConfigurationManagement;
private final SystemSecurityContext systemSecurityContext;
private WeightValidationHelper(final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.systemSecurityContext = systemSecurityContext;
this.tenantConfigurationManagement = tenantConfigurationManagement;
}
/**
* Setting the context of the tenant
*
* @param systemSecurityContext
* security context used to get the tenant and for execution
* @param tenantConfigurationManagement
* to get the value from
*/
public static WeightValidationHelper usingContext(final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
return new WeightValidationHelper(systemSecurityContext, tenantConfigurationManagement);
}
/**
* Validating weights associated with all the {@link DeploymentRequest}s
*
* @param deploymentRequests
* the {@linkplain List} of {@link DeploymentRequest}s
*/
public void validate(final List<DeploymentRequest> deploymentRequests) {
final long assignmentsWithWeight = deploymentRequests.stream()
.filter(request -> request.getTargetWithActionType().getWeight() != null).count();
final boolean containsAssignmentWithWeight = assignmentsWithWeight > 0;
final boolean containsAssignmentWithoutWeight = assignmentsWithWeight < deploymentRequests.size();
validateWeight(containsAssignmentWithWeight, containsAssignmentWithoutWeight);
}
/**
* Validating weight associated with the {@link Rollout}
*
* @param rollout
* the {@linkplain Rollout}
*/
public void validate(final Rollout rollout) {
validateWeight(rollout.getWeight().orElse(null));
}
/**
* Validating weight associated with the target filter query
*
* @param targetFilterQueryCreate
* the target filter query
*/
public void validate(final JpaTargetFilterQueryCreate targetFilterQueryCreate) {
validateWeight(targetFilterQueryCreate.getAutoAssignWeight().orElse(null));
}
/**
* Validating weight associated with the auto assignment
*
* @param autoAssignDistributionSetUpdate
* the auto assignment distribution set update
*/
public void validate(final AutoAssignDistributionSetUpdate autoAssignDistributionSetUpdate) {
validateWeight(autoAssignDistributionSetUpdate.getWeight());
}
/**
* Checks if the weight is valid
*
* @param weight
* weight tied to the rollout, auto assignment, or online
* assignment.
*/
public void validateWeight(final Integer weight) {
final boolean hasWeight = weight != null;
validateWeight(hasWeight, !hasWeight);
}
/**
* Checks if the weight is valid with the multi-assignments being turned
* off/on.
*
* @param hasWeight
* indicator of the weight if it has numerical value
* @param hasNoWeight
* indicator of the weight if it doesn't have a numerical value
*/
public void validateWeight(final boolean hasWeight, final boolean hasNoWeight) {
// remove bypassing the weight enforcement as soon as weight can be set
// via UI
final boolean bypassWeightEnforcement = true;
final boolean multiAssignmentsEnabled = TenantConfigHelper
.usingContext(systemSecurityContext, tenantConfigurationManagement).isMultiAssignmentsEnabled();
if (!multiAssignmentsEnabled && hasWeight) {
throw new MultiAssignmentIsNotEnabledException();
} else if (bypassWeightEnforcement) {
return;
} else if (multiAssignmentsEnabled && hasNoWeight) {
throw new NoWeightProvidedInMultiAssignmentModeException();
}
}
}

View File

@@ -0,0 +1,3 @@
ALTER TABLE sp_action ADD weight INT;
ALTER TABLE sp_rollout ADD weight INT;
ALTER TABLE sp_target_filter_query ADD auto_assign_weight INT;

View File

@@ -0,0 +1,3 @@
ALTER TABLE sp_action ADD weight INT;
ALTER TABLE sp_rollout ADD weight INT;
ALTER TABLE sp_target_filter_query ADD auto_assign_weight INT;

View File

@@ -0,0 +1,3 @@
ALTER TABLE sp_action ADD weight INT;
ALTER TABLE sp_rollout ADD weight INT;
ALTER TABLE sp_target_filter_query ADD auto_assign_weight INT;

View File

@@ -0,0 +1,3 @@
ALTER TABLE sp_action ADD weight INT;
ALTER TABLE sp_rollout ADD weight INT;
ALTER TABLE sp_target_filter_query ADD auto_assign_weight INT;

View File

@@ -105,5 +105,4 @@ public class RemoteIdEventTest extends AbstractRemoteEventTest {
// gets added because events inherit from of java.util.EventObject
assertThat(underTestCreatedEvent).isEqualToIgnoringGivenFields(event, "source");
}
}

View File

@@ -98,5 +98,4 @@ public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
assertThat(actionProperties).isEqualToComparingFieldByField(new ActionProperties(action));
assertThat(underTest.getDistributionSetId()).isEqualTo(action.getDistributionSet().getId());
}
}

View File

@@ -104,7 +104,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(controllerManagement.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(),
module.getId())).isNotPresent();
assertThat(controllerManagement.findOldestActiveActionByTarget(NOT_EXIST_ID)).isNotPresent();
assertThat(controllerManagement.findActiveActionWithHighestWeight(NOT_EXIST_ID)).isNotPresent();
assertThat(controllerManagement.hasTargetArtifactAssigned(target.getControllerId(), "XXX")).isFalse();
assertThat(controllerManagement.hasTargetArtifactAssigned(target.getId(), "XXX")).isFalse();
@@ -457,7 +457,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
.getContent();
assertThat(actionStatusList.get(actionStatusList.size() - 1).getStatus()).isEqualTo(expectedActionStatus);
if (actionActive) {
assertThat(controllerManagement.findOldestActiveActionByTarget(controllerId).get().getId())
assertThat(controllerManagement.findActiveActionWithHighestWeight(controllerId).get().getId())
.isEqualTo(actionId);
}
}
@@ -501,7 +501,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Register a controller which does not exist")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 2)})
@Expect(type = TargetPollEvent.class, count = 2) })
public void findOrRegisterTargetIfItDoesNotExist() {
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
assertThat(target).as("target should not be null").isNotNull();
@@ -517,7 +517,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetPollEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 1) })
public void findOrRegisterTargetIfItDoesNotExistWithName() {
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName");
final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST,
final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST,
"ChangedTestName");
assertThat(target.getId()).as("Target should be the equals").isEqualTo(sameTarget.getId());
assertThat(target.getName()).as("Taget names should be different").isNotEqualTo(sameTarget.getName());
@@ -560,8 +560,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST));
verify(mockTargetRepository, times(TX_RT_MAX)).findOne(any());
}
finally {
} finally {
// revert
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
}
@@ -597,22 +596,23 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Register a controller which does not exist, then update the controller twice, first time by providing a name property and second time without a new name")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 3) ,
@Expect(type = TargetUpdatedEvent.class, count = 1)})
@Expect(type = TargetPollEvent.class, count = 3), @Expect(type = TargetUpdatedEvent.class, count = 1) })
public void findOrRegisterTargetIfItDoesNotExistDoesUpdateNameOnExistingTargetProperly() {
String controllerId = "12345";
String targetName = "UpdatedName";
final String controllerId = "12345";
final String targetName = "UpdatedName";
final Target newTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST);
final Target newTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST);
assertThat(newTarget.getName()).isEqualTo(controllerId);
Target firstTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST, targetName);
final Target firstTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId,
LOCALHOST, targetName);
assertThat(firstTimeUpdatedTarget.getName()).isEqualTo(targetName);
//Name should not change to default (name=targetId) if target is updated without new name provided
Target secondTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST);
// Name should not change to default (name=targetId) if target is
// updated without new name provided
final Target secondTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId,
LOCALHOST);
assertThat(secondTimeUpdatedTarget.getName()).isEqualTo(targetName);
}
@@ -633,8 +633,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("1234", LOCALHOST));
verify(mockTargetRepository, times(1)).findOne(any());
verify(mockTargetRepository, times(1)).save(any());
}
finally {
} finally {
// revert
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
}
@@ -651,13 +650,11 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
when(mockTargetRepository.findOne(any())).thenThrow(RuntimeException.class);
try {
assertThatExceptionOfType(RuntimeException.class)
.as("Expected a RuntimeException to be thrown!")
assertThatExceptionOfType(RuntimeException.class).as("Expected a RuntimeException to be thrown!")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("aControllerId",
LOCALHOST));
verify(mockTargetRepository, times(1)).findOne(any());
}
finally {
} finally {
// revert
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
}
@@ -1054,9 +1051,8 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
Collections.singletonMap(keyValid, valueTooLong), null));
assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with key NULL should not be created")
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId,
Collections.singletonMap(keyNull, valueValid), null));
.as("Attribute with key NULL should not be created").isThrownBy(() -> controllerManagement
.updateControllerAttributes(controllerId, Collections.singletonMap(keyNull, valueValid), null));
}
@Test
@@ -1298,9 +1294,9 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(actionId).isNotNull();
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates").isThrownBy(
() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates")
@@ -1326,18 +1322,18 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(actionId).isNotNull();
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
.isThrownBy( ()-> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates").isThrownBy(
() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates")
.isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR))));
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates")
.isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED))));
}
@@ -1472,6 +1468,39 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertActionStatus(actionId, controllerId, TargetUpdateStatus.IN_SYNC, actionStatus, actionStatus, false);
}
@Test
@Description("Actions are exposed according to thier weight in multi assignment mode.")
public void actionsAreExposedAccordingToTheirWeight() {
final String targetId = testdataFactory.createTarget().getControllerId();
final DistributionSet ds = testdataFactory.createDistributionSet();
final Long actionWeightNull = assignDistributionSet(ds.getId(), targetId).getAssignedEntity().get(0).getId();
enableMultiAssignments();
final Long actionWeight500old = assignDistributionSet(ds.getId(), targetId, 500).getAssignedEntity().get(0)
.getId();
final Long actionWeight500new = assignDistributionSet(ds.getId(), targetId, 500).getAssignedEntity().get(0)
.getId();
final Long actionWeight1000 = assignDistributionSet(ds.getId(), targetId, 1000).getAssignedEntity().get(0)
.getId();
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
.isEqualTo(actionWeightNull);
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeightNull).status(Status.FINISHED));
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
.isEqualTo(actionWeight1000);
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight1000).status(Status.FINISHED));
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
.isEqualTo(actionWeight500old);
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight500old).status(Status.FINISHED));
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
.isEqualTo(actionWeight500new);
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight500new).status(Status.FINISHED));
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId)).isEmpty();
}
private void assertAssignedDistributionSetId(final String controllerId, final Long dsId) {
final Optional<Target> target = controllerManagement.getByControllerId(controllerId);
assertThat(target).isPresent();
@@ -1494,12 +1523,10 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(actionRepository.activeActionExistsForControllerId(controllerId)).isEqualTo(false);
}
@Test
@Description("Delete a target on requested target deletion from client side")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TargetDeletedEvent.class, count = 1)})
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1), @Expect(type = TargetDeletedEvent.class, count = 1) })
public void deleteTargetWithValidThingId() {
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
assertThat(target).as("target should not be null").isNotNull();
@@ -1512,7 +1539,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Delete a target with a non existing thingId")
@ExpectEvents({@Expect(type = TargetDeletedEvent.class, count = 0)})
@ExpectEvents({ @Expect(type = TargetDeletedEvent.class, count = 0) })
public void deleteTargetWithInvalidThingId() {
assertThatExceptionOfType(EntityNotFoundException.class)
.as("No EntityNotFoundException thrown when deleting a non-existing target")
@@ -1522,9 +1549,8 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Delete a target after it has been deleted already")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TargetDeletedEvent.class, count = 1)})
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1), @Expect(type = TargetDeletedEvent.class, count = 1) })
public void deleteTargetAfterItWasDeleted() {
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
assertThat(target).as("target should not be null").isNotNull();

View File

@@ -22,6 +22,8 @@ import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolationException;
import org.assertj.core.api.Assertions;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.DeploymentManagement;
@@ -171,7 +173,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
}
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> assignDistributionSet(ds1, Collections.singletonList(testTarget)));
.isThrownBy(() -> assignDistributionSet(ds1.getId(), testTarget.getControllerId(), 77));
}
@Test
@@ -563,16 +565,17 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
public void previousAssignmentsAreNotCanceledInMultiAssignMode() {
enableMultiAssignments();
final List<Target> targets = testdataFactory.createTargets(10);
final List<String> targetIds = targets.stream().map(Target::getControllerId).collect(Collectors.toList());
// First assignment
final DistributionSet ds1 = testdataFactory.createDistributionSet("Multi-assign-1");
assignDistributionSet(ds1, targets);
assignDistributionSet(ds1.getId(), targetIds, 77);
assertDsExclusivelyAssignedToTargets(targets, ds1.getId(), STATE_ACTIVE, Status.RUNNING);
// Second assignment
final DistributionSet ds2 = testdataFactory.createDistributionSet("Multi-assign-2");
assignDistributionSet(ds2, targets);
assignDistributionSet(ds2.getId(), targetIds, 45);
assertDsExclusivelyAssignedToTargets(targets, ds2.getId(), STATE_ACTIVE, Status.RUNNING);
assertDsExclusivelyAssignedToTargets(targets, ds1.getId(), STATE_ACTIVE, Status.RUNNING);
@@ -601,7 +604,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
public void multiassignmentInOneRequest() {
final List<Target> targets = testdataFactory.createTargets(2);
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(2);
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(distributionSets, targets);
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(distributionSets, targets, 34);
enableMultiAssignments();
final List<DistributionSetAssignmentResult> results = deploymentManagement
@@ -614,7 +617,14 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
.stream().map(action -> action.getDistributionSet().getId()).collect(Collectors.toList());
assertThat(assignedDsIds).containsExactlyInAnyOrderElementsOf(dsIds);
});
}
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight) {
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
distributionSets.forEach(ds -> targets.forEach(target -> deploymentRequests.add(DeploymentManagement
.deploymentRequest(target.getControllerId(), ds.getId()).setWeight(weight).build())));
return deploymentRequests;
}
@Test
@@ -624,9 +634,10 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(2);
final DeploymentRequest targetToDS0 = DeploymentManagement
.deploymentRequest(target.getControllerId(), distributionSets.get(0).getId()).build();
.deploymentRequest(target.getControllerId(), distributionSets.get(0).getId()).setWeight(78).build();
final DeploymentRequest targetToDS1 = DeploymentManagement
.deploymentRequest(target.getControllerId(), distributionSets.get(1).getId()).build();
.deploymentRequest(target.getControllerId(), distributionSets.get(1).getId()).setWeight(565).build();
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
.isThrownBy(() -> deploymentManagement.assignDistributionSets(Arrays.asList(targetToDS0, targetToDS1)));
@@ -638,17 +649,26 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Duplicate Assignments are removed from a request when multiassignment is disabled, otherwise not")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 3), @Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = MultiActionEvent.class, count = 1) })
public void duplicateAssignmentsInRequestAreOnlyRemovedIfMultiassignmentDisabled() {
final Target target = testdataFactory.createTarget();
final DistributionSet ds = testdataFactory.createDistributionSet();
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final List<DeploymentRequest> twoEqualAssignments = Collections.nCopies(2,
DeploymentManagement.deploymentRequest(target.getControllerId(), ds.getId()).build());
DeploymentManagement.deploymentRequest(targetId, dsId).build());
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignments)))
.isEqualTo(1);
enableMultiAssignments();
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignments)))
final List<DeploymentRequest> twoEqualAssignmentsWithWeight = Collections.nCopies(2,
DeploymentManagement.deploymentRequest(targetId, dsId).setWeight(555).build());
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignmentsWithWeight)))
.isEqualTo(2);
}
@@ -668,7 +688,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final Long dsId = testdataFactory.createDistributionSet().getId();
final List<DeploymentRequest> deploymentRequests = Collections.nCopies(maxActions + 1,
DeploymentManagement.deploymentRequest(controllerId, dsId).build());
DeploymentManagement.deploymentRequest(controllerId, dsId).setWeight(24).build());
enableMultiAssignments();
Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class)
@@ -676,6 +696,67 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(actionRepository.countByTargetControllerId(controllerId)).isEqualTo(0);
}
@Test
@Description("An assignment request without a weight is ok when multi assignment in enabled.")
public void weightNotRequiredInMultiAssignmentMode() {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final DeploymentRequest assignWithoutWeight = DeploymentManagement.deploymentRequest(targetId, dsId).build();
final DeploymentRequest assignWithWeight = DeploymentManagement.deploymentRequest(targetId, dsId).setWeight(567)
.build();
enableMultiAssignments();
deploymentManagement.assignDistributionSets(Arrays.asList(assignWithoutWeight, assignWithWeight));
}
@Test
@Description("An assignment request containing a weight causes an error when multi assignment in disabled.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
public void weightNotAllowedWhenMultiAssignmentModeNotEnabled() {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final DeploymentRequest assignWithoutWeight = DeploymentManagement.deploymentRequest(targetId, dsId)
.setWeight(456).build();
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class).isThrownBy(
() -> deploymentManagement.assignDistributionSets(Collections.singletonList(assignWithoutWeight)));
}
@Test
@Description("Weights are validated and contained in the resulting Action.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = MultiActionEvent.class, count = 2) })
public void weightValidatedAndSaved() {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final DeploymentRequest valideRequest1 = DeploymentManagement.deploymentRequest(targetId, dsId)
.setWeight(Action.WEIGHT_MAX).build();
final DeploymentRequest valideRequest2 = DeploymentManagement.deploymentRequest(targetId, dsId)
.setWeight(Action.WEIGHT_MIN).build();
final DeploymentRequest weightTooLow = DeploymentManagement.deploymentRequest(targetId, dsId)
.setWeight(Action.WEIGHT_MIN - 1).build();
final DeploymentRequest weightTooHigh = DeploymentManagement.deploymentRequest(targetId, dsId)
.setWeight(Action.WEIGHT_MAX + 1).build();
enableMultiAssignments();
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> deploymentManagement.assignDistributionSets(Collections.singletonList(weightTooLow)));
Assertions.assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
() -> deploymentManagement.assignDistributionSets(Collections.singletonList(weightTooHigh)));
final Long valideActionId1 = getFirstAssignedAction(
deploymentManagement.assignDistributionSets(Collections.singletonList(valideRequest1)).get(0)).getId();
final Long valideActionId2 = getFirstAssignedAction(
deploymentManagement.assignDistributionSets(Collections.singletonList(valideRequest2)).get(0)).getId();
assertThat(actionRepository.getById(valideActionId1).get().getWeight()).get().isEqualTo(Action.WEIGHT_MAX);
assertThat(actionRepository.getById(valideActionId2).get().getWeight()).get().isEqualTo(Action.WEIGHT_MIN);
}
/**
* test a simple deployment by calling the
* {@link TargetRepository#assignDistributionSet(DistributionSet, Iterable)}
@@ -1143,13 +1224,15 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Tests the computation of already assigned entities returned as a result of an assignment")
public void testAlreadyAssignedAndAssignedActionsInAssignmentResult(){
// create target1, distributionSet, assign ds to target1 and finish update (close all actions)
public void testAlreadyAssignedAndAssignedActionsInAssignmentResult() {
// create target1, distributionSet, assign ds to target1 and finish
// update (close all actions)
final Action action = prepareFinishedUpdate("target1", "ds", false);
final Target target2 = testdataFactory.createTarget("target2");
final Target target3 = testdataFactory.createTarget("target3");
// assign ds to target2, but don't finish update (actions should be still open)
// assign ds to target2, but don't finish update (actions should be
// still open)
assignDistributionSet(action.getDistributionSet().getId(), target2.getControllerId());
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(
@@ -1283,7 +1366,5 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
public List<Long> getUndeployedTargetIDs() {
return undeployedTargetIDs;
}
}
}

View File

@@ -17,12 +17,15 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.Condition;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
@@ -42,6 +45,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
@@ -126,7 +130,6 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
final Action rolloutCreatedAction = actionsByKnownTarget.stream()
.filter(action -> !action.getId().equals(manuallyAssignedActionId)).findAny().get();
assertThat(rolloutCreatedAction.getStatus()).isEqualTo(Status.FINISHED);
}
@Test
@@ -599,7 +602,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
final String successCondition = "50";
final String errorCondition = "80";
final Rollout createdRollout = createSimpleTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout,
amountOtherTargets, amountGroups, successCondition, errorCondition, ActionType.DOWNLOAD_ONLY);
amountOtherTargets, amountGroups, successCondition, errorCondition, ActionType.DOWNLOAD_ONLY, null);
// targets have not started
Map<TotalTargetCountStatus.Status, Long> validationMap = createInitStatusMap();
@@ -619,7 +622,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
rolloutManagement.handleRollouts();
// 4 targets are ready, 2 are finished(with DOWNLOADED action status) and 2 are running
// 4 targets are ready, 2 are finished(with DOWNLOADED action status)
// and 2 are running
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.SCHEDULED, 4L);
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 2L);
@@ -628,7 +632,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
rolloutManagement.handleRollouts();
// 2 targets are ready, 4 are finished(with DOWNLOADED action status) and 2 are running
// 2 targets are ready, 4 are finished(with DOWNLOADED action status)
// and 2 are running
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.SCHEDULED, 2L);
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 4L);
@@ -637,7 +642,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
rolloutManagement.handleRollouts();
// 0 targets are ready, 6 are finished(with DOWNLOADED action status) and 2 are running
// 0 targets are ready, 6 are finished(with DOWNLOADED action status)
// and 2 are running
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 6L);
validationMap.put(TotalTargetCountStatus.Status.RUNNING, 2L);
@@ -645,7 +651,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
changeStatusForAllRunningActions(createdRollout, Status.FINISHED);
rolloutManagement.handleRollouts();
// 0 targets are ready, 6 are finished(with DOWNLOADED action status), 2 are finished and 0 are running
// 0 targets are ready, 6 are finished(with DOWNLOADED action status), 2
// are finished and 0 are running
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 8L);
validateRolloutActionStatus(createdRollout.getId(), validationMap);
@@ -1745,14 +1752,80 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
// verify that all running actions keep running
assertThat(actionRepository.findByRolloutIdAndStatus(PAGE, deletedRollout.getId(), Status.RUNNING)
.getNumberOfElements()).isEqualTo(2);
}
@Test
@Description("Creating a rollout without weight value when multi assignment in enabled.")
public void weightNotRequiredInMultiAssignmentMode() {
enableMultiAssignments();
createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10, 2, "50", "80", ActionType.FORCED, null);
}
@Test
@Description("Creating a rollout with a weight causes an error when multi assignment in disabled.")
public void weightNotAllowedWhenMultiAssignmentModeNotEnabled() {
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
.isThrownBy(() -> createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10, 2, "50", "80",
ActionType.FORCED, 66));
}
@Test
@Description("Weight is validated and saved to the Rollout.")
public void weightValidatedAndSaved() {
final String targetPrefix = UUID.randomUUID().toString();
testdataFactory.createTargets(4, targetPrefix);
enableMultiAssignments();
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> createTestRolloutWithTargetsAndDistributionSet(4, 2, "50", "80",
UUID.randomUUID().toString(), UUID.randomUUID().toString(), Action.WEIGHT_MAX + 1));
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> createTestRolloutWithTargetsAndDistributionSet(4, 2, "50", "80",
UUID.randomUUID().toString(), UUID.randomUUID().toString(), Action.WEIGHT_MIN - 1));
final Rollout createdRollout1 = createTestRolloutWithTargetsAndDistributionSet(4, 2, "50", "80",
UUID.randomUUID().toString(), UUID.randomUUID().toString(), Action.WEIGHT_MAX);
final Rollout createdRollout2 = createTestRolloutWithTargetsAndDistributionSet(4, 2, "50", "80",
UUID.randomUUID().toString(), UUID.randomUUID().toString(), Action.WEIGHT_MIN);
assertThat(rolloutRepository.findById(createdRollout1.getId()).get().getWeight()).get()
.isEqualTo(Action.WEIGHT_MAX);
assertThat(rolloutRepository.findById(createdRollout2.getId()).get().getWeight()).get()
.isEqualTo(Action.WEIGHT_MIN);
}
@Test
@Description("A Rollout with weight creats actions with weights")
public void actionsWithWeightAreCreated() {
final int amountOfTargets = 5;
final int weight = 99;
enableMultiAssignments();
final Long rolloutId = createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2, amountOfTargets,
"80", "50", null, weight).getId();
rolloutManagement.start(rolloutId);
rolloutManagement.handleRollouts();
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
assertThat(actions).hasSize(amountOfTargets);
assertThat(actions).allMatch(action -> action.getWeight().get() == weight);
}
@Test
@Description("Rollout can be created without weight in single assignment and be started in multi assignment")
public void createInSingleStartInMultiassigMode() {
final int amountOfTargets = 5;
final Long rolloutId = createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2, amountOfTargets,
"80", "50", null, null).getId();
enableMultiAssignments();
rolloutManagement.start(rolloutId);
rolloutManagement.handleRollouts();
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
assertThat(actions).hasSize(amountOfTargets);
assertThat(actions).allMatch(action -> !action.getWeight().isPresent());
}
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage,
final String targetFilter) {
return entityFactory.rolloutGroup().create().name("Group" + index).description("Group" + index + "desc")
.targetPercentage(Float.valueOf(percentage)).targetFilterQuery(targetFilter);
}
private RolloutCreate generateTargetsAndRollout(final String rolloutName, final int amountTargetsForRollout) {
@@ -1790,27 +1863,35 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
final int amountOtherTargets, final int groupSize, final String successCondition,
final String errorCondition) {
return createSimpleTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout, amountOtherTargets,
groupSize, successCondition, errorCondition, ActionType.FORCED);
groupSize, successCondition, errorCondition, ActionType.FORCED, null);
}
private Rollout createSimpleTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
final int amountOtherTargets, final int groupSize, final String successCondition,
final String errorCondition, final ActionType actionType) {
final String errorCondition, final ActionType actionType, final Integer weight) {
final DistributionSet rolloutDS = testdataFactory.createDistributionSet("rolloutDS");
testdataFactory.createTargets(amountTargetsForRollout, "rollout-", "rollout");
testdataFactory.createTargets(amountOtherTargets, "others-", "rollout");
final String filterQuery = "controllerId==rollout-*";
return testdataFactory.createRolloutByVariables("test-rollout-name-1", "test-rollout-description-1", groupSize,
filterQuery, rolloutDS, successCondition, errorCondition, actionType);
filterQuery, rolloutDS, successCondition, errorCondition, actionType, weight);
}
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
final String targetPrefixName) {
return createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout, groupSize, successCondition,
errorCondition, rolloutName, targetPrefixName, null);
}
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
final String targetPrefixName, final Integer weight) {
final DistributionSet dsForRolloutTwo = testdataFactory.createDistributionSet("dsFor" + rolloutName);
testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName);
return testdataFactory.createRolloutByVariables(rolloutName, rolloutName + "description", groupSize,
"controllerId==" + targetPrefixName + "-*", dsForRolloutTwo, successCondition, errorCondition);
"controllerId==" + targetPrefixName + "-*", dsForRolloutTwo, successCondition, errorCondition,
Action.ActionType.FORCED, weight);
}
private int changeStatusForAllRunningActions(final Rollout rollout, final Status status) {

View File

@@ -20,6 +20,9 @@ import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import javax.validation.ConstraintViolationException;
import org.assertj.core.api.Assertions;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
@@ -28,8 +31,10 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryCreat
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
@@ -82,13 +87,18 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
verifyThrownExceptionBy(
() -> targetFilterQueryManagement.update(entityFactory.targetFilterQuery().update(NOT_EXIST_IDL)),
"TargetFilterQuery");
verifyThrownExceptionBy(
() -> targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), NOT_EXIST_IDL),
verifyThrownExceptionBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(NOT_EXIST_IDL)),
"DistributionSet");
verifyThrownExceptionBy(() -> targetFilterQueryManagement.updateAutoAssignDS(NOT_EXIST_IDL, set.getId()),
"TargetFilterQuery");
verifyThrownExceptionBy(
() -> targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), NOT_EXIST_IDL),
() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(NOT_EXIST_IDL).ds(set.getId())),
"TargetFilterQuery");
verifyThrownExceptionBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(NOT_EXIST_IDL)),
"DistributionSet");
}
@@ -208,23 +218,26 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
@Step
private void verifyAutoAssignmentWithDefaultActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId());
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()));
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.FORCED);
}
@Step
private void verifyAutoAssignmentWithSoftActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement.updateAutoAssignDSWithActionType(targetFilterQuery.getId(), distributionSet.getId(),
ActionType.SOFT);
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()).actionType(ActionType.SOFT));
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.SOFT);
}
@Step
private void verifyAutoAssignmentWithDownloadOnlyActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement.updateAutoAssignDSWithActionType(targetFilterQuery.getId(), distributionSet.getId(),
ActionType.DOWNLOAD_ONLY);
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId())
.ds(distributionSet.getId()).actionType(ActionType.DOWNLOAD_ONLY));
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.DOWNLOAD_ONLY);
}
@@ -233,9 +246,11 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
final DistributionSet distributionSet) {
// assigning a distribution set with TIMEFORCED action is supposed to
// fail as only FORCED and SOFT action types are allowed
assertThatExceptionOfType(InvalidAutoAssignActionTypeException.class).isThrownBy(
() -> targetFilterQueryManagement.updateAutoAssignDSWithActionType(targetFilterQuery.getId(),
distributionSet.getId(), ActionType.TIMEFORCED));
assertThatExceptionOfType(InvalidAutoAssignActionTypeException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId())
.ds(distributionSet.getId()).actionType(ActionType.TIMEFORCED)));
}
@Step
@@ -245,8 +260,8 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
.type(testdataFactory.findOrCreateDefaultTestDsType()));
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(),
incompleteDistributionSet.getId()));
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(incompleteDistributionSet.getId())));
}
@Step
@@ -255,8 +270,9 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
assignDistributionSet(softDeletedDs, testdataFactory.createTarget("forSoftDeletedDs"));
distributionSetManagement.delete(softDeletedDs.getId());
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class).isThrownBy(
() -> targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), softDeletedDs.getId()));
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(softDeletedDs.getId())));
}
private void verifyAutoAssignDsAndActionType(final String filterName, final DistributionSet distributionSet,
@@ -282,8 +298,10 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
// assigning a distribution set is supposed to fail as the query
// addresses too many targets
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement
.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId()));
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId())));
}
@Test
@@ -313,7 +331,8 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId());
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()));
// Check if target filter query is there
TargetFilterQuery tfq = targetFilterQueryManagement.getByName(filterName).get();
@@ -340,9 +359,11 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
// later step
assignDistributionSet(distributionSet.getId(), target.getControllerId());
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQueryManagement
final Long filterId = targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterName).query("name==PendingTargets001"))
.getId(), distributionSet.getId());
.getId();
targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(distributionSet.getId()));
// Check if target filter query is there with the distribution set
TargetFilterQuery tfq = targetFilterQueryManagement.getByName(filterName).get();
@@ -372,20 +393,18 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
final DistributionSet distributionSet2 = testdataFactory.createDistributionSet("2");
final TargetFilterQuery tfq = targetFilterQueryManagement.updateAutoAssignDSWithActionType(
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("c").query("name==x")).getId(),
distributionSet.getId(), ActionType.SOFT);
final TargetFilterQuery tfq2 = targetFilterQueryManagement.updateAutoAssignDS(
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterName).query("name==z*")).getId(),
distributionSet2.getId());
final TargetFilterQuery tfq = targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("c").query("name==x")
.autoAssignDistributionSet(distributionSet).autoAssignActionType(ActionType.SOFT));
final TargetFilterQuery tfq2 = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
.name(filterName).query("name==z*").autoAssignDistributionSet(distributionSet2));
assertEquals(4L, targetFilterQueryManagement.count());
// check if find works
verifyFindByDistributionSetAndRsql(distributionSet, null, tfq);
targetFilterQueryManagement.updateAutoAssignDS(tfq2.getId(), distributionSet.getId());
targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(tfq2.getId()).ds(distributionSet.getId()));
// check if find works for two
verifyFindByDistributionSetAndRsql(distributionSet, null, tfq, tfq2);
@@ -421,4 +440,73 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
verifyExpectedFilterQueriesInList(tfqList, expectedFilterQueries);
}
@Test
@Description("Creating or updating a target filter query with autoassignment and no-value weight when multi assignment in enabled.")
public void weightNotRequiredInMultiAssignmentMode() {
enableMultiAssignments();
final DistributionSet ds = testdataFactory.createDistributionSet();
final Long filterId = targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")).getId();
targetFilterQueryManagement.create(
entityFactory.targetFilterQuery().create().name("b").query("name==*").autoAssignDistributionSet(ds));
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()));
}
@Test
@Description("Creating or updating a target filter query with autoassignment with a weight causes an error when multi assignment in disabled.")
public void weightNotAllowedWhenMultiAssignmentModeNotEnabled() {
final DistributionSet ds = testdataFactory.createDistributionSet();
final Long filterId = targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")).getId();
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
.isThrownBy(() -> targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
.name("b").query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(342)));
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()).weight(343)));
}
@Test
@Description("Auto assignment can be removed from filter when multi assignment in enabled.")
public void removeDsFromFilterWhenMultiAssignmentModeNotEnabled() {
enableMultiAssignments();
final DistributionSet ds = testdataFactory.createDistributionSet();
final Long filterId = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a")
.query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(23)).getId();
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(null).weight(null));
}
@Test
@Description("Weight is validated and saved to the Filter.")
public void weightValidatedAndSaved() {
enableMultiAssignments();
final DistributionSet ds = testdataFactory.createDistributionSet();
Assertions.assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
() -> targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a")
.query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(Action.WEIGHT_MAX + 1)));
final Long filterId = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a")
.query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(Action.WEIGHT_MAX)).getId();
assertThat(targetFilterQueryManagement.get(filterId).get().getAutoAssignWeight().get())
.isEqualTo(Action.WEIGHT_MAX);
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(filterId).ds(ds.getId()).weight(Action.WEIGHT_MAX + 1)));
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(filterId).ds(ds.getId()).weight(Action.WEIGHT_MIN - 1)));
targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()).weight(Action.WEIGHT_MAX));
targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()).weight(Action.WEIGHT_MIN));
assertThat(targetFilterQueryManagement.get(filterId).get().getAutoAssignWeight().get())
.isEqualTo(Action.WEIGHT_MIN);
}
}

View File

@@ -131,7 +131,8 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
// try to find several targets with different filter settings
verifyThat1TargetHasNameAndId("targ-A-special", targSpecialName.getControllerId());
verifyThat1TargetHasAttributeValue("%c-attribute%", targAttribute.getControllerId());
verifyThat1TargetHasAttributeValue("%" + targAttributeId.getControllerId() + "%", targAttributeId.getControllerId());
verifyThat1TargetHasAttributeValue("%" + targAttributeId.getControllerId() + "%",
targAttributeId.getControllerId());
verifyThatRepositoryContains400Targets();
verifyThat200TargetsHaveTagD(targTagW, concat(targBs, targCs));
verifyThat100TargetsContainsGivenTextAndHaveTagAssigned(targTagY, targTagW, targBs);

View File

@@ -63,8 +63,8 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
// target filter query that matches all targets
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("filterA").query("name==*"));
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), secondDistributionSet.getId());
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(secondDistributionSet.getId()));
// Run the check
autoAssignChecker.check();
@@ -101,7 +101,8 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
// target filter query that matches all targets
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("filterA").query("name==*"));
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), setA.getId());
targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(setA.getId()));
final String targetDsAIdPref = "targ";
final List<Target> targets = testdataFactory.createTargets(100, targetDsAIdPref,
@@ -150,18 +151,16 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
// target filter query that matches first bunch of targets, that should
// fail
assertThatExceptionOfType(
InvalidAutoAssignDistributionSetException.class)
.isThrownBy(
() -> targetFilterQueryManagement.updateAutoAssignDS(
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
.name("filterA").query("id==" + targetDsFIdPref + "*")).getId(),
setF.getId()));
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class).isThrownBy(() -> {
final Long filterId = targetFilterQueryManagement.create(
entityFactory.targetFilterQuery().create().name("filterA").query("id==" + targetDsFIdPref + "*"))
.getId();
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(setF.getId()));
});
// target filter query that matches failed bunch of targets
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQueryManagement.create(
entityFactory.targetFilterQuery().create().name("filterB").query("id==" + targetDsAIdPref + "*"))
.getId(), setA.getId());
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("filterB")
.query("id==" + targetDsAIdPref + "*").autoAssignDistributionSet(setA.getId()));
final List<Target> targetsF = testdataFactory.createTargets(10, targetDsFIdPref,
targetDsFIdPref.concat(" description"));
@@ -243,12 +242,10 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
final List<Target> targets = testdataFactory.createTargets(targetCount, "target" + prefix,
prefix.concat(" description"));
targetFilterQueryManagement.create(
entityFactory.targetFilterQuery().create().name("filter" + prefix).query("id==target" + prefix + "*")
.autoAssignDistributionSet(distributionSet).autoAssignActionType(actionType));
targetFilterQueryManagement
.updateAutoAssignDSWithActionType(
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
.name("filter" + prefix).query("id==target" + prefix + "*")).getId(),
distributionSet.getId(), actionType);
return targets;
}
@@ -262,4 +259,38 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
assertThat(actions).allMatch(action -> action.getActionType().equals(actionType));
}
@Test
@Description("An auto assignment target filter with weight creats actions with weights")
public void actionsWithWeightAreCreated() throws Exception {
final int amountOfTargets = 5;
final DistributionSet ds = testdataFactory.createDistributionSet();
final int weight = 32;
enableMultiAssignments();
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")
.autoAssignDistributionSet(ds).autoAssignWeight(weight));
testdataFactory.createTargets(amountOfTargets);
autoAssignChecker.check();
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
assertThat(actions).hasSize(amountOfTargets);
assertThat(actions).allMatch(action -> action.getWeight().get() == weight);
}
@Test
@Description("An auto assignment target filter without weight still works after multi assignment is enabled")
public void filterWithoutWeightWorksInMultiAssignmentMode() throws Exception {
final int amountOfTargets = 5;
final DistributionSet ds = testdataFactory.createDistributionSet();
targetFilterQueryManagement.create(
entityFactory.targetFilterQuery().create().name("a").query("name==*").autoAssignDistributionSet(ds));
enableMultiAssignments();
testdataFactory.createTargets(amountOfTargets);
autoAssignChecker.check();
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
assertThat(actions).hasSize(amountOfTargets);
assertThat(actions).allMatch(action -> !action.getWeight().isPresent());
}
}

View File

@@ -46,6 +46,7 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
action.setDistributionSet(dsA);
action.setTarget(target);
action.setStatus(Status.RUNNING);
action.setWeight(45);
target.addAction(action);
actionRepository.save(action);
@@ -56,6 +57,7 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
newAction.setActive(i % 2 == 0);
newAction.setStatus(Status.RUNNING);
newAction.setTarget(target);
newAction.setWeight(45);
actionRepository.save(newAction);
target.addAction(newAction);
}

View File

@@ -41,14 +41,10 @@ public class RSQLTargetFilterQueryFieldsTest extends AbstractJpaIntegrationTest
final DistributionSet ds1 = testdataFactory.createDistributionSet("AutoAssignedDs_1");
final DistributionSet ds2 = testdataFactory.createDistributionSet("AutoAssignedDs_2");
filter1 = targetFilterQueryManagement.updateAutoAssignDSWithActionType(
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterName1).query("name==*")).getId(),
ds1.getId(), ActionType.SOFT);
filter2 = targetFilterQueryManagement.updateAutoAssignDS(
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterName2).query("name==*")).getId(),
ds2.getId());
filter1 = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(filterName1)
.query("name==*").autoAssignDistributionSet(ds1).autoAssignActionType(ActionType.SOFT));
filter2 = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(filterName2)
.query("name==*").autoAssignDistributionSet(ds2));
targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterName3).query("name==*"));