Introduce basic functionality for invalidation of distributionsets (#1179)
* Basic DS invalidation functionality Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Add checks for valid/complete DS Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Stop rollouts + auto assignments when invalidating a DS Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Add methods to count AAs + rollouts for invalidation Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Small refactoring for DS management Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Add invalidation functionality to REST API Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Fix update stopped rollouts status Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Add various tests Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Introduce countActionsForInvalidation Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Fix event tests with incomplete DS Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Add H2 migration script Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Fix action count method Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Fix REST documentation tests Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Change flyway version number Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Add lock for DS invalidation + adapt tests Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Move concurrency test to own class Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Handle possible InterruptedException Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Fix concurrency test Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Use one transaction for all invalidations Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Add invalidate endpoint to REST docu Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Execute invalidation in transaction when actions are cancelled Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Check that distribution set is valid when editing/creating metadata Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Remove all changes in UI Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Add DB migration files for all databases Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Implement review findings Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Move DS invalidation to own class to check permissions for single steps Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Move invalidation count methods to management classes Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com> * Fix failing tests Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com>
This commit is contained in:
committed by
GitHub
parent
b25e118e6c
commit
825cb64448
@@ -64,6 +64,28 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
*/
|
||||
Page<Action> findByDistributionSetId(Pageable pageable, Long dsId);
|
||||
|
||||
/**
|
||||
* Retrieves all active {@link Action}s which are referring the given
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param set
|
||||
* the {@link DistributionSet} on which will be filtered
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
List<Action> findByDistributionSetAndActiveIsTrue(DistributionSet set);
|
||||
|
||||
/**
|
||||
* Retrieves all active {@link Action}s which are referring the given
|
||||
* {@link DistributionSet} and are not in the given state
|
||||
*
|
||||
* @param set
|
||||
* the {@link DistributionSet} on which will be filtered
|
||||
* @param status
|
||||
* the state the actions should not have
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
List<Action> findByDistributionSetAndActiveIsTrueAndStatusIsNot(DistributionSet set, Status status);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are referring the given
|
||||
* {@link Target}.
|
||||
@@ -103,7 +125,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
* 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
|
||||
@@ -117,7 +139,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* 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
|
||||
@@ -131,7 +153,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Checks if an active action exists for given
|
||||
* {@link Target#getControllerId()}.
|
||||
*
|
||||
*
|
||||
* @param controllerId
|
||||
* of target to check
|
||||
* @return <code>true</code> if an active action for the target exists.
|
||||
@@ -264,10 +286,9 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
List<Action> findByExternalRefInAndActive(@Param("externalRefs") List<String> externalRefs,
|
||||
@Param("active") boolean active);
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves an {@link Action} that matches the queried externalRef.
|
||||
*
|
||||
*
|
||||
* @param externalRef
|
||||
* of the action. See {@link Action#getExternalRef()}
|
||||
* @return the found {@link Action}
|
||||
@@ -351,6 +372,27 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
*/
|
||||
Long countByDistributionSetId(Long distributionSet);
|
||||
|
||||
/**
|
||||
* Counts all active {@link Action}s referring to the given DistributionSet.
|
||||
*
|
||||
* @param distributionSet
|
||||
* DistributionSet to count the {@link Action}s from
|
||||
* @return the count of actions referring to the given distributionSet
|
||||
*/
|
||||
Long countByDistributionSetIdAndActiveIsTrue(Long distributionSet);
|
||||
|
||||
/**
|
||||
* Counts all active {@link Action}s referring to the given DistributionSet
|
||||
* that are not in a given state.
|
||||
*
|
||||
* @param distributionSet
|
||||
* DistributionSet to count the {@link Action}s from
|
||||
* @param status
|
||||
* the state the actions should not have
|
||||
* @return the count of actions referring to the given distributionSet
|
||||
*/
|
||||
Long countByDistributionSetIdAndActiveIsTrueAndStatusIsNot(Long distributionSet, Status status);
|
||||
|
||||
/**
|
||||
* Counts all actions referring to a given rollout and rolloutgroup which
|
||||
* are currently not in the given status. An in-clause statement does not
|
||||
@@ -396,7 +438,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Counts all actions referring to a given rollout and status.
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout the actions belong to
|
||||
* @param status
|
||||
@@ -409,7 +451,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Returns {@code true} if actions for the given rollout exists, otherwise
|
||||
* {@code false}
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout the actions belong to
|
||||
* @return {@code true} if actions for the given rollout exists, otherwise
|
||||
@@ -421,7 +463,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Returns {@code true} if actions for the given rollout exists, otherwise
|
||||
* {@code false}
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout the actions belong to
|
||||
* @param status
|
||||
@@ -471,7 +513,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Retrieves all actions for a specific rollout and in a specific status.
|
||||
*
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param rolloutId
|
||||
@@ -528,7 +570,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Deletes all actions with the given IDs.
|
||||
*
|
||||
*
|
||||
* @param actionIDs
|
||||
* the IDs of the actions to be deleted.
|
||||
*/
|
||||
|
||||
@@ -35,6 +35,7 @@ import javax.persistence.criteria.Root;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ActionFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
@@ -43,7 +44,6 @@ import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEv
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
@@ -67,6 +67,7 @@ import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -130,6 +131,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
private final EntityManager entityManager;
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
private final TargetRepository targetRepository;
|
||||
private final ActionStatusRepository actionStatusRepository;
|
||||
@@ -146,6 +148,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
private final RetryTemplate retryTemplate;
|
||||
|
||||
protected JpaDeploymentManagement(final EntityManager entityManager, final ActionRepository actionRepository,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||
@@ -156,6 +159,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
super(actionRepository, repositoryProperties);
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.targetRepository = targetRepository;
|
||||
this.actionStatusRepository = actionStatusRepository;
|
||||
this.auditorProvider = auditorProvider;
|
||||
@@ -254,8 +258,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
/**
|
||||
* method assigns the {@link DistributionSet} to all {@link Target}s by
|
||||
* their IDs with a specific {@link ActionType} and {@code forcetime}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* In case the update was executed offline (i.e. not managed by hawkBit) the
|
||||
* handling differs my means that:<br/>
|
||||
* A. it ignores targets completely that are in
|
||||
@@ -285,7 +289,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
final Collection<TargetWithActionType> targetsWithActionType, final String actionMessage,
|
||||
final AbstractDsAssignmentStrategy assignmentStrategy) {
|
||||
|
||||
final JpaDistributionSet distributionSetEntity = getAndValidateDsById(dsID);
|
||||
final JpaDistributionSet distributionSetEntity = (JpaDistributionSet) distributionSetManagement
|
||||
.getValidAndComplete(dsID);
|
||||
final List<String> providedTargetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId)
|
||||
.distinct().collect(Collectors.toList());
|
||||
|
||||
@@ -363,18 +368,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
return new DistributionSetAssignmentResult(distributionSet, alreadyAssignedTargetsCount, assignedActions);
|
||||
}
|
||||
|
||||
private JpaDistributionSet getAndValidateDsById(final Long dsID) {
|
||||
final JpaDistributionSet distributionSet = distributionSetRepository.findById(dsID)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, dsID));
|
||||
|
||||
if (!distributionSet.isComplete()) {
|
||||
throw new IncompleteDistributionSetException("Distribution set of type "
|
||||
+ distributionSet.getType().getKey() + " is incomplete: " + distributionSet.getId());
|
||||
}
|
||||
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
private void checkQuotaForAssignment(final Collection<DeploymentRequest> deploymentRequests) {
|
||||
if (!deploymentRequests.isEmpty()) {
|
||||
enforceMaxAssignmentsPerRequest(deploymentRequests.size());
|
||||
@@ -656,8 +649,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
private Specification<JpaAction> createSpecificationFor(final String controllerId, final String rsqlParam) {
|
||||
final Specification<JpaAction> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer,
|
||||
database);
|
||||
final Specification<JpaAction> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class,
|
||||
virtualPropertyReplacer, database);
|
||||
return (root, query, cb) -> cb.and(spec.toPredicate(root, query, cb),
|
||||
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.controllerId), controllerId));
|
||||
}
|
||||
@@ -779,6 +772,17 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
return actionRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionsByDistributionSetIdAndActiveIsTrue(final Long distributionSet) {
|
||||
return actionRepository.countByDistributionSetIdAndActiveIsTrue(distributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionsByDistributionSetIdAndActiveIsTrueAndStatusIsNot(final Long distributionSet,
|
||||
final Status status) {
|
||||
return actionRepository.countByDistributionSetIdAndActiveIsTrueAndStatusIsNot(distributionSet, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Action> findActionsByDistributionSet(final Pageable pageable, final long dsId) {
|
||||
throwExceptionIfDistributionSetDoesNotExist(dsId);
|
||||
@@ -832,7 +836,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPendingCancellations(String controllerId) {
|
||||
public boolean hasPendingCancellations(final String controllerId) {
|
||||
return actionRepository.existsByTargetControllerIdAndStatusAndActiveIsTrue(controllerId,
|
||||
Action.Status.CANCELING);
|
||||
}
|
||||
@@ -881,4 +885,21 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void cancelActionsForDistributionSet(final CancelationType cancelationType, final DistributionSet set) {
|
||||
actionRepository.findByDistributionSetAndActiveIsTrueAndStatusIsNot(set, Status.CANCELING).forEach(action -> {
|
||||
final JpaAction jpaAction = (JpaAction) action;
|
||||
cancelAction(jpaAction.getId());
|
||||
LOG.debug("Action {} canceled", jpaAction.getId());
|
||||
});
|
||||
if (cancelationType == CancelationType.FORCE) {
|
||||
actionRepository.findByDistributionSetAndActiveIsTrue(set).forEach(action -> {
|
||||
final JpaAction jpaAction = (JpaAction) action;
|
||||
forceQuitAction(jpaAction.getId());
|
||||
LOG.debug("Action {} force canceled", jpaAction.getId());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO 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.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.StopRolloutException;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidationCount;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.integration.support.locks.LockRegistry;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* Jpa implementation for {@link DistributionSetInvalidationManagement}
|
||||
*
|
||||
*/
|
||||
public class JpaDistributionSetInvalidationManagement implements DistributionSetInvalidationManagement {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JpaDistributionSetInvalidationManagement.class);
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final RolloutManagement rolloutManagement;
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
private final PlatformTransactionManager txManager;
|
||||
private final RepositoryProperties repositoryProperties;
|
||||
private final TenantAware tenantAware;
|
||||
private final LockRegistry lockRegistry;
|
||||
|
||||
protected JpaDistributionSetInvalidationManagement(final DistributionSetManagement distributionSetManagement,
|
||||
final RolloutManagement rolloutManagement, final DeploymentManagement deploymentManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final PlatformTransactionManager txManager,
|
||||
final RepositoryProperties repositoryProperties, final TenantAware tenantAware,
|
||||
final LockRegistry lockRegistry) {
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.rolloutManagement = rolloutManagement;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.txManager = txManager;
|
||||
this.repositoryProperties = repositoryProperties;
|
||||
this.tenantAware = tenantAware;
|
||||
this.lockRegistry = lockRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateDistributionSet(final DistributionSetInvalidation distributionSetInvalidation) {
|
||||
LOG.debug("Invalidate distribution sets {}", distributionSetInvalidation.getDistributionSetIds());
|
||||
final String tenant = tenantAware.getCurrentTenant();
|
||||
|
||||
if (shouldRolloutsBeCanceled(distributionSetInvalidation.getCancelationType(),
|
||||
distributionSetInvalidation.isCancelRollouts())) {
|
||||
final String handlerId = JpaRolloutManagement.createRolloutLockKey(tenant);
|
||||
final Lock lock = lockRegistry.obtain(handlerId);
|
||||
try {
|
||||
if (!lock.tryLock(repositoryProperties.getDsInvalidationLockTimeout(), TimeUnit.SECONDS)) {
|
||||
throw new StopRolloutException("Timeout while trying to invalidate distribution sets");
|
||||
}
|
||||
try {
|
||||
invalidateDistributionSetsInTransaction(distributionSetInvalidation, tenant);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} catch (final InterruptedException e) {
|
||||
LOG.error("InterruptedException while invalidating distribution sets {}!",
|
||||
distributionSetInvalidation.getDistributionSetIds(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} else {
|
||||
// no lock is needed as no rollout will be stopped
|
||||
invalidateDistributionSetsInTransaction(distributionSetInvalidation, tenant);
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidateDistributionSetsInTransaction(final DistributionSetInvalidation distributionSetInvalidation,
|
||||
final String tenant) {
|
||||
DeploymentHelper.runInNewTransaction(txManager, tenant + "-invalidateDS", status -> {
|
||||
distributionSetInvalidation.getDistributionSetIds().forEach(setId -> invalidateDistributionSet(setId,
|
||||
distributionSetInvalidation.getCancelationType(), distributionSetInvalidation.isCancelRollouts()));
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
private void invalidateDistributionSet(final long setId, final CancelationType cancelationType,
|
||||
final boolean cancelRollouts) {
|
||||
final DistributionSet set = distributionSetManagement.getValidAndComplete(setId);
|
||||
distributionSetManagement.invalidate(set);
|
||||
LOG.debug("Distribution set {} set to invalid", setId);
|
||||
|
||||
if (shouldRolloutsBeCanceled(cancelationType, cancelRollouts)) {
|
||||
rolloutManagement.cancelRolloutsForDistributionSet(set);
|
||||
}
|
||||
|
||||
if (cancelationType != CancelationType.NONE) {
|
||||
deploymentManagement.cancelActionsForDistributionSet(cancelationType, set);
|
||||
}
|
||||
|
||||
targetFilterQueryManagement.cancelAutoAssignmentForDistributionSet(setId);
|
||||
}
|
||||
|
||||
private static boolean shouldRolloutsBeCanceled(final CancelationType cancelationType,
|
||||
final boolean cancelRollouts) {
|
||||
return cancelationType != CancelationType.NONE || cancelRollouts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSetInvalidationCount countEntitiesForInvalidation(
|
||||
final DistributionSetInvalidation distributionSetInvalidation) {
|
||||
final Collection<Long> setIds = distributionSetInvalidation.getDistributionSetIds();
|
||||
final long rolloutsCount = shouldRolloutsBeCanceled(distributionSetInvalidation.getCancelationType(),
|
||||
distributionSetInvalidation.isCancelRollouts()) ? countRolloutsForInvalidation(setIds) : 0;
|
||||
final long autoAssignmentsCount = countAutoAssignmentsForInvalidation(setIds);
|
||||
final long actionsCount = countActionsForInvalidation(setIds, distributionSetInvalidation.getCancelationType());
|
||||
|
||||
return new DistributionSetInvalidationCount(rolloutsCount, autoAssignmentsCount, actionsCount);
|
||||
}
|
||||
|
||||
private long countRolloutsForInvalidation(final Collection<Long> setIds) {
|
||||
return setIds.stream().mapToLong(rolloutManagement::countByDistributionSetIdAndRolloutIsStoppable).sum();
|
||||
}
|
||||
|
||||
private long countAutoAssignmentsForInvalidation(final Collection<Long> setIds) {
|
||||
return setIds.stream().mapToLong(targetFilterQueryManagement::countByAutoAssignDistributionSetId).sum();
|
||||
}
|
||||
|
||||
private long countActionsForInvalidation(final Collection<Long> setIds, final CancelationType cancelationType) {
|
||||
long affectedActionsByDSInvalidation = 0;
|
||||
if (cancelationType == CancelationType.FORCE) {
|
||||
affectedActionsByDSInvalidation = countActionsForForcedInvalidation(setIds);
|
||||
} else if (cancelationType == CancelationType.SOFT) {
|
||||
affectedActionsByDSInvalidation = countActionsForSoftInvalidation(setIds);
|
||||
}
|
||||
return affectedActionsByDSInvalidation;
|
||||
}
|
||||
|
||||
private long countActionsForForcedInvalidation(final Collection<Long> setIds) {
|
||||
return setIds.stream().mapToLong(deploymentManagement::countActionsByDistributionSetIdAndActiveIsTrue).sum();
|
||||
}
|
||||
|
||||
private long countActionsForSoftInvalidation(final Collection<Long> setIds) {
|
||||
return setIds.stream().mapToLong(distributionSet -> deploymentManagement
|
||||
.countActionsByDistributionSetIdAndActiveIsTrueAndStatusIsNot(distributionSet, Status.CANCELING)).sum();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,8 @@ import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
@@ -213,7 +215,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
public DistributionSet update(final DistributionSetUpdate u) {
|
||||
final GenericDistributionSetUpdate update = (GenericDistributionSetUpdate) u;
|
||||
|
||||
final JpaDistributionSet set = findDistributionSetAndThrowExceptionIfNotFound(update.getId());
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(update.getId());
|
||||
|
||||
update.getName().ifPresent(set::setName);
|
||||
update.getDescription().ifPresent(set::setDescription);
|
||||
@@ -228,11 +230,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
return distributionSetRepository.save(set);
|
||||
}
|
||||
|
||||
private JpaDistributionSet findDistributionSetAndThrowExceptionIfNotFound(final Long setId) {
|
||||
return (JpaDistributionSet) get(setId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, setId));
|
||||
}
|
||||
|
||||
private JpaSoftwareModule findSoftwareModuleAndThrowExceptionIfNotFound(final Long moduleId) {
|
||||
return softwareModuleRepository.findById(moduleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, moduleId));
|
||||
@@ -315,7 +312,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
assertDistributionSetIsNotAssignedToTargets(setId);
|
||||
|
||||
final JpaDistributionSet set = findDistributionSetAndThrowExceptionIfNotFound(setId);
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(setId);
|
||||
|
||||
assertSoftwareModuleQuota(setId, modules.size());
|
||||
|
||||
@@ -329,7 +326,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSet unassignSoftwareModule(final long setId, final long moduleId) {
|
||||
final JpaDistributionSet set = findDistributionSetAndThrowExceptionIfNotFound(setId);
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(setId);
|
||||
final JpaSoftwareModule module = findSoftwareModuleAndThrowExceptionIfNotFound(moduleId);
|
||||
|
||||
assertDistributionSetIsNotAssignedToTargets(setId);
|
||||
@@ -531,7 +528,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
* of the DS to touch
|
||||
*/
|
||||
private JpaDistributionSet touch(final Long distId) {
|
||||
return touch(get(distId).orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, distId)));
|
||||
return touch(getValid(distId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -595,7 +592,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
private static List<Specification<JpaDistributionSet>> buildDistributionSetSpecifications(
|
||||
final DistributionSetFilter distributionSetFilter) {
|
||||
final List<Specification<JpaDistributionSet>> specList = Lists.newArrayListWithExpectedSize(8);
|
||||
final List<Specification<JpaDistributionSet>> specList = Lists.newArrayListWithExpectedSize(9);
|
||||
|
||||
Specification<JpaDistributionSet> spec;
|
||||
|
||||
@@ -609,6 +606,11 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
specList.add(spec);
|
||||
}
|
||||
|
||||
if (distributionSetFilter.getIsValid() != null) {
|
||||
spec = DistributionSetSpecification.isValid(distributionSetFilter.getIsValid());
|
||||
specList.add(spec);
|
||||
}
|
||||
|
||||
if (distributionSetFilter.getType() != null) {
|
||||
spec = DistributionSetSpecification.byType(distributionSetFilter.getType());
|
||||
specList.add(spec);
|
||||
@@ -781,8 +783,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
public Page<DistributionSet> findByRsqlAndTag(final Pageable pageable, final String rsqlParam, final long tagId) {
|
||||
throwEntityNotFoundExceptionIfDsTagDoesNotExist(tagId);
|
||||
|
||||
final Specification<JpaDistributionSet> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetFields.class,
|
||||
virtualPropertyReplacer, database);
|
||||
final Specification<JpaDistributionSet> spec = RSQLUtility.buildRsqlSpecification(rsqlParam,
|
||||
DistributionSetFields.class, virtualPropertyReplacer, database);
|
||||
|
||||
return convertDsPage(findByCriteriaAPI(pageable, Arrays.asList(spec, DistributionSetSpecification.hasTag(tagId),
|
||||
DistributionSetSpecification.isDeleted(false))), pageable);
|
||||
@@ -797,8 +799,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
@Override
|
||||
public Page<DistributionSet> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||
final Specification<JpaDistributionSet> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetFields.class,
|
||||
virtualPropertyReplacer, database);
|
||||
final Specification<JpaDistributionSet> spec = RSQLUtility.buildRsqlSpecification(rsqlParam,
|
||||
DistributionSetFields.class, virtualPropertyReplacer, database);
|
||||
|
||||
return convertDsPage(
|
||||
findByCriteriaAPI(pageable, Arrays.asList(spec, DistributionSetSpecification.isDeleted(false))),
|
||||
@@ -815,4 +817,41 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
return distributionSetRepository.existsById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSet getOrElseThrowException(final long id) {
|
||||
return get(id).orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSet getValidAndComplete(final long id) {
|
||||
final DistributionSet distributionSet = getValid(id);
|
||||
|
||||
if (!distributionSet.isComplete()) {
|
||||
throw new IncompleteDistributionSetException("Distribution set of type "
|
||||
+ distributionSet.getType().getKey() + " is incomplete: " + distributionSet.getId());
|
||||
}
|
||||
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSet getValid(final long id) {
|
||||
final DistributionSet distributionSet = getOrElseThrowException(id);
|
||||
|
||||
if (!distributionSet.isValid()) {
|
||||
throw new InvalidDistributionSetException("Distribution set of type " + distributionSet.getType().getKey()
|
||||
+ " is invalid: " + distributionSet.getId());
|
||||
}
|
||||
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void invalidate(final DistributionSet set) {
|
||||
final JpaDistributionSet jpaSet = (JpaDistributionSet) set;
|
||||
jpaSet.invalidate();
|
||||
distributionSetRepository.save(jpaSet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.RolloutHelper;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.RolloutGroupDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.RolloutStoppedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||
@@ -155,6 +156,9 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
||||
case RUNNING:
|
||||
handleRunningRollout((JpaRollout) rollout);
|
||||
break;
|
||||
case STOPPING:
|
||||
handleStopRollout((JpaRollout) rollout);
|
||||
break;
|
||||
default:
|
||||
LOGGER.error("Rollout in status {} not supposed to be handled!", rollout.getStatus());
|
||||
break;
|
||||
@@ -244,6 +248,39 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
||||
sendRolloutGroupDeletedEvents(rollout);
|
||||
}
|
||||
|
||||
private void handleStopRollout(final JpaRollout rollout) {
|
||||
LOGGER.debug("handleStopRollout called for {}", rollout.getId());
|
||||
// clean up all scheduled actions
|
||||
final Slice<JpaAction> scheduledActions = findScheduledActionsByRollout(rollout);
|
||||
deleteScheduledActions(rollout, scheduledActions);
|
||||
|
||||
// avoid another scheduler round and re-check if all scheduled actions
|
||||
// has been cleaned up. we flush first to ensure that the we include the
|
||||
// deletion above
|
||||
entityManager.flush();
|
||||
final boolean hasScheduledActionsLeft = actionRepository.countByRolloutIdAndStatus(rollout.getId(),
|
||||
Status.SCHEDULED) > 0;
|
||||
|
||||
if (hasScheduledActionsLeft) {
|
||||
return;
|
||||
}
|
||||
|
||||
rolloutGroupRepository.findByRolloutAndStatusNotIn(rollout,
|
||||
Arrays.asList(RolloutGroupStatus.FINISHED, RolloutGroupStatus.ERROR)).forEach(rolloutGroup -> {
|
||||
rolloutGroup.setStatus(RolloutGroupStatus.FINISHED);
|
||||
rolloutGroupRepository.save(rolloutGroup);
|
||||
});
|
||||
|
||||
rollout.setStatus(RolloutStatus.FINISHED);
|
||||
rolloutRepository.save(rollout);
|
||||
|
||||
final List<Long> groupIds = rollout.getRolloutGroups().stream().map(RolloutGroup::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(new RolloutStoppedEvent(
|
||||
tenantAware.getCurrentTenant(), eventPublisherHolder.getApplicationId(), rollout.getId(), groupIds)));
|
||||
}
|
||||
|
||||
private void handleReadyRollout(final Rollout rollout) {
|
||||
if (rollout.getStartAt() != null && rollout.getStartAt() <= System.currentTimeMillis()) {
|
||||
LOGGER.debug(
|
||||
|
||||
@@ -100,7 +100,12 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JpaRolloutManagement.class);
|
||||
|
||||
private static final List<RolloutStatus> ACTIVE_ROLLOUTS = Arrays.asList(RolloutStatus.CREATING,
|
||||
RolloutStatus.DELETING, RolloutStatus.STARTING, RolloutStatus.READY, RolloutStatus.RUNNING);
|
||||
RolloutStatus.DELETING, RolloutStatus.STARTING, RolloutStatus.READY, RolloutStatus.RUNNING,
|
||||
RolloutStatus.STOPPING);
|
||||
|
||||
private static final List<RolloutStatus> ROLLOUT_STATUS_STOPPABLE = Arrays.asList(RolloutStatus.RUNNING,
|
||||
RolloutStatus.CREATING, RolloutStatus.PAUSED, RolloutStatus.READY, RolloutStatus.STARTING,
|
||||
RolloutStatus.WAITING_FOR_APPROVAL, RolloutStatus.APPROVAL_DENIED);
|
||||
|
||||
@Autowired
|
||||
private RolloutRepository rolloutRepository;
|
||||
@@ -126,8 +131,8 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
|
||||
private final Database database;
|
||||
|
||||
public JpaRolloutManagement(final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
|
||||
final RolloutGroupManagement rolloutGroupManagement,
|
||||
public JpaRolloutManagement(final TargetManagement targetManagement,
|
||||
final DeploymentManagement deploymentManagement, final RolloutGroupManagement rolloutGroupManagement,
|
||||
final DistributionSetManagement distributionSetManagement, final ApplicationContext context,
|
||||
final EventPublisherHolder eventPublisherHolder, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final PlatformTransactionManager txManager, final TenantAware tenantAware, final LockRegistry lockRegistry,
|
||||
@@ -151,7 +156,8 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
@Override
|
||||
public Page<Rollout> findByRsql(final Pageable pageable, final String rsqlParam, final boolean deleted) {
|
||||
final List<Specification<JpaRollout>> specList = Lists.newArrayListWithExpectedSize(2);
|
||||
specList.add(RSQLUtility.buildRsqlSpecification(rsqlParam, RolloutFields.class, virtualPropertyReplacer, database));
|
||||
specList.add(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, RolloutFields.class, virtualPropertyReplacer, database));
|
||||
specList.add(RolloutSpecification.isDeletedWithDistributionSet(deleted));
|
||||
|
||||
return JpaRolloutHelper.convertPage(findByCriteriaAPI(pageable, specList), pageable);
|
||||
@@ -400,7 +406,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
|
||||
final String tenant = tenantAware.getCurrentTenant();
|
||||
|
||||
final String handlerId = tenant + "-rollout";
|
||||
final String handlerId = createRolloutLockKey(tenant);
|
||||
final Lock lock = lockRegistry.obtain(handlerId);
|
||||
if (!lock.tryLock()) {
|
||||
return;
|
||||
@@ -414,6 +420,10 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
}
|
||||
}
|
||||
|
||||
public static String createRolloutLockKey(final String tenant) {
|
||||
return tenant + "-rollout";
|
||||
}
|
||||
|
||||
private long handleRollout(final long rolloutId) {
|
||||
final JpaRollout rollout = rolloutRepository.findById(rolloutId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||
@@ -451,6 +461,11 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
return rolloutRepository.count(JpaRolloutHelper.likeNameOrDescription(searchText, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByDistributionSetIdAndRolloutIsStoppable(final long setId) {
|
||||
return rolloutRepository.countByDistributionSetIdAndStatusIn(setId, ROLLOUT_STATUS_STOPPABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Rollout> findByFiltersWithDetailedStatus(final Pageable pageable, final String searchText,
|
||||
final boolean deleted) {
|
||||
@@ -483,8 +498,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
// null
|
||||
rollout.setStartAt(update.getStartAt().orElse(null));
|
||||
update.getSet().ifPresent(setId -> {
|
||||
final DistributionSet set = distributionSetManagement.get(setId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, setId));
|
||||
final DistributionSet set = distributionSetManagement.getValidAndComplete(setId);
|
||||
|
||||
rollout.setDistributionSet(set);
|
||||
});
|
||||
@@ -596,7 +610,20 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
}
|
||||
|
||||
private void runInUserContext(final BaseEntity rollout, final Runnable handler) {
|
||||
DeploymentHelper.runInNonSystemContext(handler, () -> Objects.requireNonNull(rollout.getCreatedBy()), tenantAware);
|
||||
DeploymentHelper.runInNonSystemContext(handler, () -> Objects.requireNonNull(rollout.getCreatedBy()),
|
||||
tenantAware);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void cancelRolloutsForDistributionSet(final DistributionSet set) {
|
||||
// stop all rollouts for this distribution set
|
||||
rolloutRepository.findByDistributionSetAndStatusIn(set, ROLLOUT_STATUS_STOPPABLE).forEach(rollout -> {
|
||||
final JpaRollout jpaRollout = (JpaRollout) rollout;
|
||||
jpaRollout.setStatus(RolloutStatus.STOPPING);
|
||||
rolloutRepository.save(jpaRollout);
|
||||
LOGGER.debug("Rollout {} stopped", jpaRollout.getId());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetFilterQueryCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
@@ -72,7 +71,7 @@ import cz.jirutka.rsql.parser.RSQLParserException;
|
||||
public class JpaTargetFilterQueryManagement implements TargetFilterQueryManagement {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JpaTargetFilterQueryManagement.class);
|
||||
|
||||
|
||||
private final TargetFilterQueryRepository targetFilterQueryRepository;
|
||||
private final TargetManagement targetManagement;
|
||||
|
||||
@@ -147,6 +146,11 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
return targetFilterQueryRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByAutoAssignDistributionSetId(final long autoAssignDistributionSetId) {
|
||||
return targetFilterQueryRepository.countByAutoAssignDistributionSetId(autoAssignDistributionSetId);
|
||||
}
|
||||
|
||||
private static Page<TargetFilterQuery> convertPage(final Page<JpaTargetFilterQuery> findAll,
|
||||
final Pageable pageable) {
|
||||
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
|
||||
@@ -165,8 +169,8 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
public Page<TargetFilterQuery> findByRsql(final Pageable pageable, final String rsqlFilter) {
|
||||
List<Specification<JpaTargetFilterQuery>> specList = Collections.emptyList();
|
||||
if (!StringUtils.isEmpty(rsqlFilter)) {
|
||||
specList = Collections.singletonList(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlFilter, TargetFilterQueryFields.class, virtualPropertyReplacer, database));
|
||||
specList = Collections.singletonList(RSQLUtility.buildRsqlSpecification(rsqlFilter,
|
||||
TargetFilterQueryFields.class, virtualPropertyReplacer, database));
|
||||
}
|
||||
return convertPage(findTargetFilterQueryByCriteriaAPI(pageable, specList), pageable);
|
||||
}
|
||||
@@ -185,13 +189,13 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
final String rsqlFilter) {
|
||||
final List<Specification<JpaTargetFilterQuery>> specList = Lists.newArrayListWithExpectedSize(2);
|
||||
|
||||
final DistributionSet distributionSet = findDistributionSetAndThrowExceptionIfNotFound(setId);
|
||||
final DistributionSet distributionSet = distributionSetManagement.getOrElseThrowException(setId);
|
||||
|
||||
specList.add(TargetFilterQuerySpecification.byAutoAssignDS(distributionSet));
|
||||
|
||||
if (!StringUtils.isEmpty(rsqlFilter)) {
|
||||
specList.add(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlFilter, TargetFilterQueryFields.class, virtualPropertyReplacer, database));
|
||||
specList.add(RSQLUtility.buildRsqlSpecification(rsqlFilter, TargetFilterQueryFields.class,
|
||||
virtualPropertyReplacer, database));
|
||||
}
|
||||
return convertPage(findTargetFilterQueryByCriteriaAPI(pageable, specList), pageable);
|
||||
}
|
||||
@@ -264,8 +268,9 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
// specify an
|
||||
// auto-assign distribution set when creating a target filter query
|
||||
assertMaxTargetsQuota(targetFilterQuery.getQuery());
|
||||
final JpaDistributionSet ds = findDistributionSetAndThrowExceptionIfNotFound(update.getDsId());
|
||||
verifyDistributionSetAndThrowExceptionIfNotValid(ds);
|
||||
final JpaDistributionSet ds = (JpaDistributionSet) distributionSetManagement
|
||||
.getValidAndComplete(update.getDsId());
|
||||
verifyDistributionSetAndThrowExceptionIfDeleted(ds);
|
||||
targetFilterQuery.setAutoAssignDistributionSet(ds);
|
||||
targetFilterQuery.setAutoAssignInitiatedBy(tenantAware.getCurrentUsername());
|
||||
targetFilterQuery.setAutoAssignActionType(sanitizeAutoAssignActionType(update.getActionType()));
|
||||
@@ -274,9 +279,9 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
return targetFilterQueryRepository.save(targetFilterQuery);
|
||||
}
|
||||
|
||||
private static void verifyDistributionSetAndThrowExceptionIfNotValid(final DistributionSet distributionSet) {
|
||||
if (!distributionSet.isComplete() || distributionSet.isDeleted()) {
|
||||
throw new InvalidAutoAssignDistributionSetException();
|
||||
private static void verifyDistributionSetAndThrowExceptionIfDeleted(final DistributionSet distributionSet) {
|
||||
if (distributionSet.isDeleted()) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, distributionSet.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,11 +297,6 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
return actionType;
|
||||
}
|
||||
|
||||
private JpaDistributionSet findDistributionSetAndThrowExceptionIfNotFound(final Long setId) {
|
||||
return (JpaDistributionSet) distributionSetManagement.get(setId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, setId));
|
||||
}
|
||||
|
||||
private JpaTargetFilterQuery findTargetFilterQueryOrThrowExceptionIfNotFound(final Long queryId) {
|
||||
return targetFilterQueryRepository.findById(queryId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, queryId));
|
||||
@@ -317,4 +317,11 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
QuotaHelper.assertAssignmentQuota(targetManagement.countByRsql(query),
|
||||
quotaManagement.getMaxTargetsPerAutoAssignment(), Target.class, TargetFilterQuery.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void cancelAutoAssignmentForDistributionSet(final long setId) {
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionType(setId);
|
||||
LOGGER.debug("Auto assignments for distribution sets {} deactivated", setId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ import org.eclipse.hawkbit.repository.jpa.rollout.condition.PauseRolloutGroupAct
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParserValidationOracle;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.DefaultRsqlVisitorFactory;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParserValidationOracle;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
@@ -238,13 +238,14 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
TargetBuilder targetBuilder(final TargetTypeManagement targetTypeManagement){
|
||||
TargetBuilder targetBuilder(final TargetTypeManagement targetTypeManagement) {
|
||||
return new JpaTargetBuilder(targetTypeManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dsTypeManagement
|
||||
* for loading {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||
* for loading
|
||||
* {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||
* @return TargetTypeBuilder bean
|
||||
*/
|
||||
@Bean
|
||||
@@ -434,7 +435,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Override
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager(
|
||||
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
|
||||
final ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
|
||||
return new MultiTenantJpaTransactionManager();
|
||||
}
|
||||
|
||||
@@ -485,12 +486,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
DistributionSetTypeManagement distributionSetTypeManagement(
|
||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final TargetTypeRepository targetTypeRepository,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
|
||||
final QuotaManagement quotaManagement) {
|
||||
return new JpaDistributionSetTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
|
||||
distributionSetRepository, targetTypeRepository, virtualPropertyReplacer, properties.getDatabase(), quotaManagement);
|
||||
distributionSetRepository, targetTypeRepository, virtualPropertyReplacer, properties.getDatabase(),
|
||||
quotaManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -541,13 +542,15 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final TargetRepository targetRepository, final TargetMetadataRepository targetMetadataRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final TargetTagRepository targetTagRepository, final EventPublisherHolder eventPublisherHolder,
|
||||
final TenantAware tenantAware, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties) {
|
||||
return new JpaTargetManagement(entityManager, quotaManagement, targetRepository, targetTypeRepository, targetMetadataRepository,
|
||||
rolloutGroupRepository, distributionSetRepository, targetFilterQueryRepository, targetTagRepository,
|
||||
eventPublisherHolder, tenantAware, afterCommit, virtualPropertyReplacer, properties.getDatabase());
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository,
|
||||
final EventPublisherHolder eventPublisherHolder, final TenantAware tenantAware,
|
||||
final AfterTransactionCommitExecutor afterCommit, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final JpaProperties properties) {
|
||||
return new JpaTargetManagement(entityManager, quotaManagement, targetRepository, targetTypeRepository,
|
||||
targetMetadataRepository, rolloutGroupRepository, distributionSetRepository,
|
||||
targetFilterQueryRepository, targetTagRepository, eventPublisherHolder, tenantAware, afterCommit,
|
||||
virtualPropertyReplacer, properties.getDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -718,17 +721,17 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@ConditionalOnMissingBean
|
||||
DeploymentManagement deploymentManagement(final EntityManager entityManager,
|
||||
final ActionRepository actionRepository, final DistributionSetRepository distributionSetRepository,
|
||||
final TargetRepository targetRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final AuditorAware<String> auditorProvider, final EventPublisherHolder eventPublisherHolder,
|
||||
final AfterTransactionCommitExecutor afterCommit, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final PlatformTransactionManager txManager,
|
||||
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
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 JpaProperties properties, final RepositoryProperties repositoryProperties) {
|
||||
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetRepository, targetRepository,
|
||||
actionStatusRepository, auditorProvider, eventPublisherHolder, afterCommit, virtualPropertyReplacer,
|
||||
txManager, tenantConfigurationManagement, quotaManagement, systemSecurityContext, tenantAware,
|
||||
properties.getDatabase(), repositoryProperties);
|
||||
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetManagement,
|
||||
distributionSetRepository, targetRepository, actionStatusRepository, auditorProvider,
|
||||
eventPublisherHolder, afterCommit, virtualPropertyReplacer, txManager, tenantConfigurationManagement,
|
||||
quotaManagement, systemSecurityContext, tenantAware, properties.getDatabase(), repositoryProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -813,7 +816,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link AutoAssignScheduler} bean.
|
||||
*
|
||||
*
|
||||
* Note: does not activate in test profile, otherwise it is hard to test the
|
||||
* auto assign functionality.
|
||||
*
|
||||
@@ -843,12 +846,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link AutoActionCleanup} bean.
|
||||
*
|
||||
*
|
||||
* @param deploymentManagement
|
||||
* Deployment management service
|
||||
* @param configManagement
|
||||
* Tenant configuration service
|
||||
*
|
||||
*
|
||||
* @return a new {@link AutoActionCleanup} bean
|
||||
*/
|
||||
@Bean
|
||||
@@ -859,7 +862,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link AutoCleanupScheduler} bean.
|
||||
*
|
||||
*
|
||||
* @param systemManagement
|
||||
* to find all tenants
|
||||
* @param systemSecurityContext
|
||||
@@ -868,7 +871,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
* to lock the tenant for auto assignment
|
||||
* @param cleanupTasks
|
||||
* a list of cleanup tasks
|
||||
*
|
||||
*
|
||||
* @return a new {@link AutoCleanupScheduler} bean
|
||||
*/
|
||||
@Bean
|
||||
@@ -883,10 +886,10 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link RolloutScheduler} bean.
|
||||
*
|
||||
*
|
||||
* Note: does not activate in test profile, otherwise it is hard to test the
|
||||
* rollout handling functionality.
|
||||
*
|
||||
*
|
||||
* @param systemManagement
|
||||
* to find all tenants
|
||||
* @param rolloutManagement
|
||||
@@ -906,7 +909,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* Creates the {@link RsqlVisitorFactory} bean.
|
||||
*
|
||||
*
|
||||
* @return A new {@link RsqlVisitorFactory} bean.
|
||||
*/
|
||||
@Bean
|
||||
@@ -917,7 +920,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* Obtains the {@link RsqlVisitorFactoryHolder} bean.
|
||||
*
|
||||
*
|
||||
* @return The {@link RsqlVisitorFactoryHolder} singleton.
|
||||
*/
|
||||
@Bean
|
||||
@@ -925,4 +928,22 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
return RsqlVisitorFactoryHolder.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaDistributionSetInvalidationManagement} bean.
|
||||
*
|
||||
* @return a new {@link JpaDistributionSetInvalidationManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
JpaDistributionSetInvalidationManagement distributionSetInvalidationManagement(
|
||||
final DistributionSetManagement distributionSetManagement, final RolloutManagement rolloutManagement,
|
||||
final DeploymentManagement deploymentManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final PlatformTransactionManager txManager,
|
||||
final RepositoryProperties repositoryProperties, final TenantAware tenantAware,
|
||||
final LockRegistry lockRegistry) {
|
||||
return new JpaDistributionSetInvalidationManagement(distributionSetManagement, rolloutManagement,
|
||||
deploymentManagement, targetFilterQueryManagement, txManager, repositoryProperties, tenantAware,
|
||||
lockRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
@@ -33,7 +34,7 @@ public interface RolloutGroupRepository
|
||||
/**
|
||||
* Retrieves all {@link RolloutGroup} referring a specific rollout in the
|
||||
* order of creating them. ID ASC.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout the rolloutgroups belong to
|
||||
* @return the rollout groups belonging to a rollout ordered by ID ASC.
|
||||
@@ -43,7 +44,7 @@ public interface RolloutGroupRepository
|
||||
/**
|
||||
* Retrieves all {@link RolloutGroup} referring a specific rollout in a
|
||||
* specific {@link RolloutGroupStatus}.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout the rolloutgroup belong to
|
||||
* @param status
|
||||
@@ -58,7 +59,7 @@ public interface RolloutGroupRepository
|
||||
* the spring-data, so this is specific usecase regarding to the
|
||||
* rollout-management to find out rolloutgroups which are in specific
|
||||
* states.
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout the rolloutgroup belong to
|
||||
* @param rolloutGroupStatus1
|
||||
@@ -74,10 +75,10 @@ public interface RolloutGroupRepository
|
||||
@Param("status2") RolloutGroupStatus rolloutGroupStatus2);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Counts all rollout-groups refering to a given {@link Rollout} by its ID
|
||||
* and groups which not having the given status.
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout refering the groups
|
||||
* @param status1
|
||||
@@ -97,7 +98,7 @@ public interface RolloutGroupRepository
|
||||
/**
|
||||
* Retrieves all {@link RolloutGroup} for a specific parent in a specific
|
||||
* status. Retrieves the child rolloutgroup for a specific status.
|
||||
*
|
||||
*
|
||||
* @param rolloutGroupId
|
||||
* the rolloutgroupId to find the parents
|
||||
* @param status
|
||||
@@ -111,7 +112,7 @@ public interface RolloutGroupRepository
|
||||
/**
|
||||
* Updates all {@link RolloutGroup#getStatus()} of children for given
|
||||
* parent.
|
||||
*
|
||||
*
|
||||
* @param parent
|
||||
* the parent rolloutgroup
|
||||
* @param status
|
||||
@@ -125,7 +126,7 @@ public interface RolloutGroupRepository
|
||||
/**
|
||||
* Retrieves all {@link RolloutGroup} for a specific rollout and status not
|
||||
* having ordered by ID DESC, latest top.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout the rolloutgroup belong to
|
||||
* @param notStatus
|
||||
@@ -135,9 +136,22 @@ public interface RolloutGroupRepository
|
||||
*/
|
||||
List<JpaRolloutGroup> findByRolloutAndStatusNotOrderByIdDesc(JpaRollout rollout, RolloutGroupStatus notStatus);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link RolloutGroup}s for a specific rollout and status not
|
||||
* having.
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout the rolloutgroup belong to
|
||||
* @param status
|
||||
* the status which the rolloutgroup should not have
|
||||
* @return rolloutgroup referring to a rollout and not having a specific
|
||||
* status.
|
||||
*/
|
||||
List<JpaRolloutGroup> findByRolloutAndStatusNotIn(JpaRollout rollout, Collection<RolloutGroupStatus> status);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link RolloutGroup} for a specific rollout.
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout to find the rollout groups
|
||||
* @param page
|
||||
@@ -148,10 +162,10 @@ public interface RolloutGroupRepository
|
||||
|
||||
/**
|
||||
* Counts all {@link RolloutGroup} for a specific rollout.
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout to find the rollout groups
|
||||
*
|
||||
*
|
||||
* @return the amount of found {@link RolloutGroup}s.
|
||||
*/
|
||||
long countByRolloutId(Long rolloutId);
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.Optional;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
@@ -33,7 +34,7 @@ public interface RolloutRepository
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Rollout} for given status.
|
||||
*
|
||||
*
|
||||
* @param status
|
||||
* the status of the rollouts to find
|
||||
* @return the list of {@link Rollout} for specific status
|
||||
@@ -44,7 +45,7 @@ public interface RolloutRepository
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Rollout} for a specific {@code name}
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* the rollout name
|
||||
* @return {@link Rollout} for specific name
|
||||
@@ -64,4 +65,28 @@ public interface RolloutRepository
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaRollout t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Rollout}s for a specific {@link DistributionSet} in
|
||||
* a given {@link RolloutStatus}.
|
||||
*
|
||||
* @param set
|
||||
* the distribution set
|
||||
* @param status
|
||||
* the status of the rollout
|
||||
* @return {@link Rollout} for specific distribution set
|
||||
*/
|
||||
List<Rollout> findByDistributionSetAndStatusIn(DistributionSet set, Collection<RolloutStatus> status);
|
||||
|
||||
/**
|
||||
* Counts all {@link Rollout}s for a specific {@link DistributionSet} in a
|
||||
* given {@link RolloutStatus}.
|
||||
*
|
||||
* @param distributionSetId
|
||||
* the distribution set
|
||||
* @param status
|
||||
* the status of the rollout
|
||||
* @return the count
|
||||
*/
|
||||
long countByDistributionSetIdAndStatusIn(long distributionSetId, Collection<RolloutStatus> status);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public interface TargetFilterQueryRepository
|
||||
|
||||
/**
|
||||
* Find customer target filter by name
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @return custom target filter
|
||||
*/
|
||||
@@ -56,6 +56,16 @@ public interface TargetFilterQueryRepository
|
||||
@Query("update JpaTargetFilterQuery d set d.autoAssignDistributionSet = NULL, d.autoAssignActionType = NULL where d.autoAssignDistributionSet in :ids")
|
||||
void unsetAutoAssignDistributionSetAndActionType(@Param("ids") Long... dsIds);
|
||||
|
||||
/**
|
||||
* Counts all target filters that have a given auto assign distribution set
|
||||
* assigned.
|
||||
*
|
||||
* @param autoAssignDistributionSetId
|
||||
* the id of the distribution set
|
||||
* @return the count
|
||||
*/
|
||||
long countByAutoAssignDistributionSetId(long autoAssignDistributionSetId);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
|
||||
@@ -11,9 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractRolloutUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
|
||||
public class JpaRolloutCreate extends AbstractRolloutUpdateCreate<RolloutCreate> implements RolloutCreate {
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
@@ -28,7 +26,7 @@ public class JpaRolloutCreate extends AbstractRolloutUpdateCreate<RolloutCreate>
|
||||
|
||||
rollout.setName(name);
|
||||
rollout.setDescription(description);
|
||||
rollout.setDistributionSet(findDistributionSetAndThrowExceptionIfNotFound(set));
|
||||
rollout.setDistributionSet(distributionSetManagement.getValidAndComplete(set));
|
||||
rollout.setTargetFilterQuery(targetFilterQuery);
|
||||
rollout.setStartAt(startAt);
|
||||
rollout.setWeight(weight);
|
||||
@@ -43,9 +41,4 @@ public class JpaRolloutCreate extends AbstractRolloutUpdateCreate<RolloutCreate>
|
||||
|
||||
return rollout;
|
||||
}
|
||||
|
||||
private DistributionSet findDistributionSetAndThrowExceptionIfNotFound(final Long setId) {
|
||||
return distributionSetManagement.get(setId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, setId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,9 @@ package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractTargetFilterQueryUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
|
||||
/**
|
||||
@@ -35,16 +33,11 @@ public class JpaTargetFilterQueryCreate extends AbstractTargetFilterQueryUpdateC
|
||||
public JpaTargetFilterQuery build() {
|
||||
|
||||
return new JpaTargetFilterQuery(name, query,
|
||||
getAutoAssignDistributionSetId().map(this::findDistributionSetAndThrowExceptionIfNotFound).orElse(null),
|
||||
getAutoAssignDistributionSetId().map(distributionSetManagement::getValidAndComplete).orElse(null),
|
||||
getAutoAssignActionType().filter(JpaTargetFilterQueryCreate::isAutoAssignActionTypeValid).orElse(null),
|
||||
weight);
|
||||
}
|
||||
|
||||
private DistributionSet findDistributionSetAndThrowExceptionIfNotFound(final Long setId) {
|
||||
return distributionSetManagement.get(setId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, setId));
|
||||
}
|
||||
|
||||
private static boolean isAutoAssignActionTypeValid(final ActionType actionType) {
|
||||
if (!TargetFilterQuery.ALLOWED_AUTO_ASSIGN_ACTION_TYPES.contains(actionType)) {
|
||||
throw new InvalidAutoAssignActionTypeException();
|
||||
|
||||
@@ -116,6 +116,9 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
@Column(name = "complete")
|
||||
private boolean complete;
|
||||
|
||||
@Column(name = "valid")
|
||||
private boolean valid;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
@@ -145,6 +148,7 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
super(name, version, description);
|
||||
|
||||
this.requiredMigrationStep = requiredMigrationStep;
|
||||
this.valid = true;
|
||||
this.type = type;
|
||||
if (moduleList != null) {
|
||||
moduleList.forEach(this::addModule);
|
||||
@@ -327,6 +331,15 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
return complete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
this.valid = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
||||
publishEventWithEventPublisher(
|
||||
|
||||
@@ -93,7 +93,8 @@ 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"),
|
||||
@ConversionValue(objectValue = "STOPPING", dataValue = "13") })
|
||||
@Convert("rolloutstatus")
|
||||
@NotNull
|
||||
private RolloutStatus status = RolloutStatus.CREATING;
|
||||
|
||||
@@ -45,7 +45,7 @@ public final class DistributionSetSpecification {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by its
|
||||
* DELETED attribute.
|
||||
*
|
||||
*
|
||||
* @param isDeleted
|
||||
* TRUE/FALSE are compared to the attribute DELETED. If NULL the
|
||||
* attribute is ignored
|
||||
@@ -59,7 +59,7 @@ public final class DistributionSetSpecification {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by its
|
||||
* COMPLETED attribute.
|
||||
*
|
||||
*
|
||||
* @param isCompleted
|
||||
* TRUE/FALSE are compared to the attribute COMPLETED. If NULL
|
||||
* the attribute is ignored
|
||||
@@ -70,6 +70,20 @@ public final class DistributionSetSpecification {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by its
|
||||
* VALID attribute.
|
||||
*
|
||||
* @param isValid
|
||||
* TRUE/FALSE are compared to the attribute VALID. If NULL the
|
||||
* attribute is ignored
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> isValid(final Boolean isValid) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.<Boolean> get(JpaDistributionSet_.valid), isValid);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet} with given
|
||||
* {@link DistributionSet#getId()}.
|
||||
@@ -111,7 +125,7 @@ public final class DistributionSetSpecification {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by "like
|
||||
* name or like description or like version".
|
||||
*
|
||||
*
|
||||
* @param subString
|
||||
* to be filtered on
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
@@ -126,7 +140,7 @@ public final class DistributionSetSpecification {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by "like
|
||||
* name and like version".
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* to be filtered on
|
||||
* @param version
|
||||
@@ -142,7 +156,7 @@ public final class DistributionSetSpecification {
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by "has at
|
||||
* least one of the given tag names".
|
||||
*
|
||||
*
|
||||
* @param tagNames
|
||||
* to be filtered on
|
||||
* @param selectDSWithNoTag
|
||||
@@ -187,7 +201,7 @@ public final class DistributionSetSpecification {
|
||||
/**
|
||||
* returns query criteria {@link Specification} comparing case insensitive
|
||||
* "NAME == AND VERSION ==".
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* to be filtered on
|
||||
* @param version
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_distribution_set ADD COLUMN valid BOOLEAN;
|
||||
|
||||
UPDATE sp_distribution_set SET valid = 1;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_distribution_set ADD COLUMN valid BOOLEAN;
|
||||
|
||||
UPDATE sp_distribution_set SET valid = 1;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_distribution_set ADD COLUMN valid BOOLEAN;
|
||||
|
||||
UPDATE sp_distribution_set SET valid = 1;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_distribution_set ADD COLUMN valid BOOLEAN;
|
||||
|
||||
UPDATE sp_distribution_set SET valid = 1;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_distribution_set ADD COLUMN valid BOOLEAN;
|
||||
|
||||
UPDATE sp_distribution_set SET valid = 1;
|
||||
@@ -8,10 +8,13 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
@@ -34,8 +37,11 @@ public class RolloutEventTest extends AbstractRemoteEntityEventTest<Rollout> {
|
||||
@Override
|
||||
protected Rollout createEntity() {
|
||||
testdataFactory.createTarget("12345");
|
||||
final DistributionSet ds = distributionSetManagement.create(entityFactory.distributionSet()
|
||||
.create().name("incomplete").version("2").description("incomplete").type("os"));
|
||||
final SoftwareModule module = softwareModuleManagement.create(
|
||||
entityFactory.softwareModule().create().name("swm").version("2").description("desc").type("os"));
|
||||
final DistributionSet ds = distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create().name("complete").version("2").description("complete")
|
||||
.type("os").modules(Collections.singletonList(module.getId())));
|
||||
|
||||
return rolloutManagement.create(
|
||||
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").set(ds),
|
||||
|
||||
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -17,6 +18,7 @@ import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
@@ -75,9 +77,11 @@ public class RolloutGroupEventTest extends AbstractRemoteEntityEventTest<Rollout
|
||||
@Override
|
||||
protected RolloutGroup createEntity() {
|
||||
testdataFactory.createTarget(UUID.randomUUID().toString());
|
||||
|
||||
final DistributionSet ds = distributionSetManagement.create(entityFactory.distributionSet().create()
|
||||
.name("incomplete").version("2").description("incomplete").type("os"));
|
||||
final SoftwareModule module = softwareModuleManagement.create(
|
||||
entityFactory.softwareModule().create().name("swm").version("2").description("desc").type("os"));
|
||||
final DistributionSet ds = distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create().name("complete").version("2").description("complete")
|
||||
.type("os").modules(Collections.singletonList(module.getId())));
|
||||
|
||||
final Rollout entity = rolloutManagement.create(
|
||||
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").set(ds),
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO 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 static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.eclipse.hawkbit.repository.exception.StopRolloutException;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
|
||||
/**
|
||||
* Test class testing the invalidation of a {@link DistributionSet} while the
|
||||
* handle rollouts is ongoing.
|
||||
*
|
||||
*/
|
||||
@Feature("Component Tests - Repository")
|
||||
@Story("Concurrent Distribution Set invalidation")
|
||||
@TestPropertySource(properties = "hawkbit.server.repository.dsInvalidationLockTimeout=1")
|
||||
public class ConcurrentDistributionSetInvalidationTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Verify that a large rollout causes a timeout when trying to invalidate a distribution set")
|
||||
public void verifyInvalidateDistributionSetWithLargeRolloutThrowsException() throws Exception {
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
testdataFactory.createTargets(10000, "verifyInvalidateDistributionSetWithLargeRolloutThrowsException");
|
||||
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults()
|
||||
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "50")
|
||||
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, "80")
|
||||
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
|
||||
final Rollout rollout = rolloutManagement.create(entityFactory.rollout().create()
|
||||
.name("verifyInvalidateDistributionSetWithLargeRolloutThrowsException").description("desc")
|
||||
.targetFilterQuery("name==*").set(distributionSet).actionType(ActionType.FORCED), 20, conditions);
|
||||
final String tenant = tenantAware.getCurrentTenant();
|
||||
|
||||
// run in new Thread so that the invalidation can be executed in
|
||||
// parallel
|
||||
final Thread handleRolloutsThread = new Thread(() -> {
|
||||
tenantAware.runAsTenant(tenant, () -> systemSecurityContext.runAsSystem(() -> {
|
||||
rolloutManagement.handleRollouts();
|
||||
return 0;
|
||||
}));
|
||||
});
|
||||
handleRolloutsThread.start();
|
||||
// wait until at least one RolloutGroup is created, as this means that
|
||||
// the thread has started and has acquired the lock
|
||||
Awaitility.await().until(() -> tenantAware.runAsTenant(tenant, () -> systemSecurityContext
|
||||
.runAsSystem(() -> rolloutGroupManagement.findByRollout(PAGE, rollout.getId()).getSize() > 0)));
|
||||
|
||||
assertThatExceptionOfType(StopRolloutException.class)
|
||||
.as("Invalidation of distributionSet should throw an exception")
|
||||
.isThrownBy(() -> distributionSetInvalidationManagement.invalidateDistributionSet(
|
||||
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
|
||||
CancelationType.SOFT, true)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
@@ -844,8 +845,8 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
* test a simple deployment by calling the
|
||||
* {@link TargetRepository#assignDistributionSet(DistributionSet, Iterable)} and
|
||||
* checking the active action and the action history of the targets.
|
||||
* {@link TargetRepository#assignDistributionSet(DistributionSet, Iterable)}
|
||||
* and checking the active action and the action history of the targets.
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
@@ -1088,9 +1089,10 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* test the deletion of {@link DistributionSet}s including exception in case of
|
||||
* {@link Target}s are assigned by {@link Target#getAssignedDistributionSet()}
|
||||
* or {@link Target#getInstalledDistributionSet()}
|
||||
* test the deletion of {@link DistributionSet}s including exception in case
|
||||
* of {@link Target}s are assigned by
|
||||
* {@link Target#getAssignedDistributionSet()} or
|
||||
* {@link Target#getInstalledDistributionSet()}
|
||||
*/
|
||||
@Test
|
||||
@Description("Deletes distribution set. Expected behaviour is that a soft delete is performed "
|
||||
@@ -1357,12 +1359,36 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(distributionSetRepository.findAll()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests that an exception is thrown when a target is assigned to an incomplete distribution set")
|
||||
public void verifyAssignTargetsToIncompleteDistribution() {
|
||||
final DistributionSet distributionSet = testdataFactory.createIncompleteDistributionSet();
|
||||
final Target target = testdataFactory.createTarget();
|
||||
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.as("Incomplete distributionSet should throw an exception")
|
||||
.isThrownBy(() -> assignDistributionSet(distributionSet, target));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests that an exception is thrown when a target is assigned to an invalidated distribution set")
|
||||
public void verifyAssignTargetsToInvalidDistribution() {
|
||||
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
final Target target = testdataFactory.createTarget();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> assignDistributionSet(distributionSet, target));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper methods that creates 2 lists of targets and a list of distribution
|
||||
* sets.
|
||||
* <p>
|
||||
* <b>All created distribution sets are assigned to all targets of the target
|
||||
* list deployedTargets.</b>
|
||||
* <b>All created distribution sets are assigned to all targets of the
|
||||
* target list deployedTargets.</b>
|
||||
*
|
||||
* @param undeployedTargetPrefix
|
||||
* prefix to be used as target controller prefix
|
||||
@@ -1371,7 +1397,8 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
* @param deployedTargetPrefix
|
||||
* prefix to be used as target controller prefix
|
||||
* @param noOfDeployedTargets
|
||||
* number of targets to which the created distribution sets assigned
|
||||
* number of targets to which the created distribution sets
|
||||
* assigned
|
||||
* @param noOfDistributionSets
|
||||
* number of distribution sets
|
||||
* @param distributionSetPrefix
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO 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 static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidationCount;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
|
||||
/**
|
||||
* Test class testing the functionality of invalidating a
|
||||
* {@link DistributionSet}
|
||||
*
|
||||
*/
|
||||
@Feature("Component Tests - Repository")
|
||||
@Story("Distribution set invalidation management")
|
||||
class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Verify invalidation of distribution sets that only removes distribution sets from auto assignments")
|
||||
void verifyInvalidateDistributionSetStopAutoAssignment() {
|
||||
final InvalidationTestData invalidationTestData = createInvalidationTestData(
|
||||
"verifyInvalidateDistributionSetStopAutoAssignment");
|
||||
|
||||
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), CancelationType.NONE,
|
||||
false);
|
||||
final DistributionSetInvalidationCount distributionSetInvalidationCount = distributionSetInvalidationManagement
|
||||
.countEntitiesForInvalidation(distributionSetInvalidation);
|
||||
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 0, 0);
|
||||
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
|
||||
rolloutManagement.handleRollouts();
|
||||
|
||||
assertThat(targetFilterQueryManagement.get(invalidationTestData.getTargetFilterQuery().getId()).get()
|
||||
.getAutoAssignDistributionSet()).isNull();
|
||||
assertThat(rolloutRepository.findById(invalidationTestData.getRollout().getId()).get().getStatus())
|
||||
.isNotIn(RolloutStatus.STOPPING, RolloutStatus.FINISHED);
|
||||
for (final Target target : invalidationTestData.getTargets()) {
|
||||
// if status is pending, the assignment has not been canceled
|
||||
assertThat(targetRepository.findById(target.getId()).get().getUpdateStatus())
|
||||
.isEqualTo(TargetUpdateStatus.PENDING);
|
||||
assertThat(actionRepository.findByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(actionRepository.findByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify invalidation of distribution sets that removes distribution sets from auto assignments and stops rollouts")
|
||||
void verifyInvalidateDistributionSetStopRollouts() {
|
||||
final InvalidationTestData invalidationTestData = createInvalidationTestData(
|
||||
"verifyInvalidateDistributionSetStopRollouts");
|
||||
|
||||
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), CancelationType.NONE,
|
||||
true);
|
||||
final DistributionSetInvalidationCount distributionSetInvalidationCount = distributionSetInvalidationManagement
|
||||
.countEntitiesForInvalidation(distributionSetInvalidation);
|
||||
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 0, 1);
|
||||
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
|
||||
rolloutManagement.handleRollouts();
|
||||
|
||||
assertThat(targetFilterQueryManagement.get(invalidationTestData.getTargetFilterQuery().getId()).get()
|
||||
.getAutoAssignDistributionSet()).isNull();
|
||||
assertThat(rolloutRepository.findById(invalidationTestData.getRollout().getId()).get().getStatus())
|
||||
.isEqualTo(RolloutStatus.FINISHED);
|
||||
assertNoScheduledActionsExist(invalidationTestData.getRollout());
|
||||
assertRolloutGroupsAreFinished(invalidationTestData.getRollout());
|
||||
for (final Target target : invalidationTestData.getTargets()) {
|
||||
// if status is pending, the assignment has not been canceled
|
||||
assertThat(
|
||||
targetRepository.findById(invalidationTestData.getTargets().get(0).getId()).get().getUpdateStatus())
|
||||
.isEqualTo(TargetUpdateStatus.PENDING);
|
||||
assertThat(actionRepository.findByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(actionRepository.findByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify invalidation of distribution sets that removes distribution sets from auto assignments, stops rollouts and force cancels assignments")
|
||||
void verifyInvalidateDistributionSetStopAllAndForceCancel() {
|
||||
final InvalidationTestData invalidationTestData = createInvalidationTestData(
|
||||
"verifyInvalidateDistributionSetStopAllAndForceCancel");
|
||||
|
||||
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), CancelationType.FORCE,
|
||||
true);
|
||||
final DistributionSetInvalidationCount distributionSetInvalidationCount = distributionSetInvalidationManagement
|
||||
.countEntitiesForInvalidation(distributionSetInvalidation);
|
||||
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 5, 1);
|
||||
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
|
||||
rolloutManagement.handleRollouts();
|
||||
|
||||
assertThat(targetFilterQueryManagement.get(invalidationTestData.getTargetFilterQuery().getId()).get()
|
||||
.getAutoAssignDistributionSet()).isNull();
|
||||
assertThat(rolloutRepository.findById(invalidationTestData.getRollout().getId()).get().getStatus())
|
||||
.isEqualTo(RolloutStatus.FINISHED);
|
||||
assertNoScheduledActionsExist(invalidationTestData.getRollout());
|
||||
assertRolloutGroupsAreFinished(invalidationTestData.getRollout());
|
||||
for (final Target target : invalidationTestData.getTargets()) {
|
||||
assertThat(targetRepository.findById(target.getId()).get().getUpdateStatus())
|
||||
.isEqualTo(TargetUpdateStatus.IN_SYNC);
|
||||
assertThat(actionRepository.findByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(actionRepository.findByTarget(target).get(0).getStatus()).isEqualTo(Status.CANCELED);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertNoScheduledActionsExist(final Rollout rollout) {
|
||||
assertThat(
|
||||
actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), Status.SCHEDULED).getTotalElements())
|
||||
.isZero();
|
||||
}
|
||||
|
||||
private void assertRolloutGroupsAreFinished(final Rollout rollout) {
|
||||
assertThat(rolloutGroupRepository.findByRolloutId(rollout.getId(), PAGE))
|
||||
.allMatch(rolloutGroup -> rolloutGroup.getStatus().equals(RolloutGroupStatus.FINISHED));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify invalidation of distribution sets that removes distribution sets from auto assignments, stops rollouts and cancels assignments")
|
||||
void verifyInvalidateDistributionSetStopAll() {
|
||||
final InvalidationTestData invalidationTestData = createInvalidationTestData(
|
||||
"verifyInvalidateDistributionSetStopAll");
|
||||
|
||||
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), CancelationType.SOFT,
|
||||
true);
|
||||
final DistributionSetInvalidationCount distributionSetInvalidationCount = distributionSetInvalidationManagement
|
||||
.countEntitiesForInvalidation(distributionSetInvalidation);
|
||||
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 5, 1);
|
||||
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
|
||||
|
||||
assertThat(targetFilterQueryManagement.get(invalidationTestData.getTargetFilterQuery().getId()).get()
|
||||
.getAutoAssignDistributionSet()).isNull();
|
||||
assertThat(rolloutRepository.findById(invalidationTestData.getRollout().getId()).get().getStatus())
|
||||
.isIn(RolloutStatus.STOPPING, RolloutStatus.FINISHED);
|
||||
for (final Target target : invalidationTestData.getTargets()) {
|
||||
assertThat(targetRepository.findById(target.getId()).get().getUpdateStatus())
|
||||
.isEqualTo(TargetUpdateStatus.PENDING);
|
||||
assertThat(actionRepository.findByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(actionRepository.findByTarget(target).get(0).getStatus()).isEqualTo(Status.CANCELING);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that invalidating an incomplete distribution set throws an exception")
|
||||
void verifyInvalidateIncompleteDistributionSetThrowsException() {
|
||||
final DistributionSet distributionSet = testdataFactory.createIncompleteDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.as("Incomplete distributionSet should throw an exception")
|
||||
.isThrownBy(() -> distributionSetInvalidationManagement.invalidateDistributionSet(
|
||||
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
|
||||
CancelationType.SOFT, true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that invalidating an invalidated distribution set throws an exception")
|
||||
void verifyInvalidateInvalidatedDistributionSetThrowsException() {
|
||||
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> distributionSetInvalidationManagement.invalidateDistributionSet(
|
||||
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
|
||||
CancelationType.SOFT, true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that a user that has authority READ_REPOSITORY and UPDATE_REPOSITORY is not allowed to invalidate a distribution set")
|
||||
@WithUser(authorities = { "READ_REPOSITORY", "UPDATE_REPOSITORY" })
|
||||
void verifyInvalidateWithReadAndUpdateRepoAuthority() {
|
||||
final InvalidationTestData invalidationTestData = systemSecurityContext
|
||||
.runAsSystem(() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAuthority"));
|
||||
|
||||
assertThatExceptionOfType(InsufficientPermissionException.class)
|
||||
.as("Insufficient permission exception expected")
|
||||
.isThrownBy(() -> distributionSetInvalidationManagement
|
||||
.invalidateDistributionSet(new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()),
|
||||
CancelationType.NONE, false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that a user that has authority READ_REPOSITORY, UPDATE_REPOSITORY and UPDATE_TARGET is allowed to invalidate a distribution set only without canceling rollouts")
|
||||
@WithUser(authorities = { "READ_REPOSITORY", "UPDATE_REPOSITORY", "UPDATE_TARGET" })
|
||||
void verifyInvalidateWithReadAndUpdateRepoAndUpdateTargetAuthority() {
|
||||
final InvalidationTestData invalidationTestData = systemSecurityContext.runAsSystem(
|
||||
() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAndUpdateTargetAuthority"));
|
||||
|
||||
assertThatExceptionOfType(InsufficientPermissionException.class)
|
||||
.as("Insufficient permission exception expected")
|
||||
.isThrownBy(() -> distributionSetInvalidationManagement
|
||||
.invalidateDistributionSet(new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()),
|
||||
CancelationType.SOFT, true)));
|
||||
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), CancelationType.NONE,
|
||||
false));
|
||||
assertThat(
|
||||
distributionSetRepository.findById(invalidationTestData.getDistributionSet().getId()).get().isValid())
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that a user that has authority READ_REPOSITORY, UPDATE_REPOSITORY, UPDATE_ROLLOUT and UPDATE_TARGET is allowed to invalidate a distribution")
|
||||
@WithUser(authorities = { "READ_REPOSITORY", "UPDATE_REPOSITORY", "UPDATE_TARGET", "UPDATE_ROLLOUT" })
|
||||
void verifyInvalidateWithReadAndUpdateRepoAndUpdateTargetAndUpdateRolloutAuthority() {
|
||||
final InvalidationTestData invalidationTestData = systemSecurityContext.runAsSystem(
|
||||
() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAndUpdateTargetAuthority"));
|
||||
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), CancelationType.SOFT,
|
||||
true));
|
||||
assertThat(
|
||||
distributionSetRepository.findById(invalidationTestData.getDistributionSet().getId()).get().isValid())
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
private InvalidationTestData createInvalidationTestData(final String testName) {
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
final List<Target> targets = testdataFactory.createTargets(5, testName);
|
||||
assignDistributionSet(distributionSet, targets);
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.create(entityFactory.targetFilterQuery()
|
||||
.create().name(testName).query("name==*").autoAssignDistributionSet(distributionSet));
|
||||
final Rollout rollout = testdataFactory.createRolloutByVariables(testName, "desc", 2, "name==*",
|
||||
distributionSet, "50", "80");
|
||||
|
||||
return new InvalidationTestData(distributionSet, targets, targetFilterQuery, rollout);
|
||||
}
|
||||
|
||||
private static class InvalidationTestData {
|
||||
private final DistributionSet distributionSet;
|
||||
private final List<Target> targets;
|
||||
private final TargetFilterQuery targetFilterQuery;
|
||||
private final Rollout rollout;
|
||||
|
||||
public InvalidationTestData(final DistributionSet distributionSet, final List<Target> targets,
|
||||
final TargetFilterQuery targetFilterQuery, final Rollout rollout) {
|
||||
super();
|
||||
this.distributionSet = distributionSet;
|
||||
this.targets = targets;
|
||||
this.targetFilterQuery = targetFilterQuery;
|
||||
this.rollout = rollout;
|
||||
}
|
||||
|
||||
public DistributionSet getDistributionSet() {
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
public List<Target> getTargets() {
|
||||
return targets;
|
||||
}
|
||||
|
||||
public TargetFilterQuery getTargetFilterQuery() {
|
||||
return targetFilterQuery;
|
||||
}
|
||||
|
||||
public Rollout getRollout() {
|
||||
return rollout;
|
||||
}
|
||||
}
|
||||
|
||||
private void assertDistributionSetInvalidationCount(
|
||||
final DistributionSetInvalidationCount distributionSetInvalidationCount,
|
||||
final long expectedAutoAssignmentCount, final long expectedActionCount, final long expectedRolloutCount) {
|
||||
assertThat(distributionSetInvalidationCount.getAutoAssignmentCount()).isEqualTo(expectedAutoAssignmentCount);
|
||||
assertThat(distributionSetInvalidationCount.getActionCount()).isEqualTo(expectedActionCount);
|
||||
assertThat(distributionSetInvalidationCount.getRolloutsCount()).isEqualTo(expectedRolloutCount);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,16 +31,20 @@ import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreated
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
@@ -174,6 +178,13 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.updateMetaData(set.getId(),
|
||||
entityFactory.generateDsMetadata(NOT_EXIST_ID, "xxx")), "DistributionSetMetadata");
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.getOrElseThrowException(NOT_EXIST_IDL),
|
||||
"DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.getValidAndComplete(NOT_EXIST_IDL), "DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(() -> distributionSetManagement.getValid(NOT_EXIST_IDL), "DistributionSet");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -493,6 +504,16 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(ds.isRequiredMigrationStep()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to update an invalid distribution set")
|
||||
public void updateInvalidDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception").isThrownBy(() -> distributionSetManagement
|
||||
.update(entityFactory.distributionSet().update(distributionSet.getId()).name("new_name")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies the enforcement of the software module quota per distribution set.")
|
||||
public void assignSoftwareModulesUntilQuotaIsExceeded() {
|
||||
@@ -533,6 +554,33 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to assign software modules to an invalidated distribution set.")
|
||||
public void verifyAssignSoftwareModulesToInvalidDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
final SoftwareModule softwareModule = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> distributionSetManagement.assignSoftwareModules(distributionSet.getId(),
|
||||
Collections.singletonList(softwareModule.getId())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to unassign a software module from an invalidated distribution set.")
|
||||
public void verifyUnassignSoftwareModulesToInvalidDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
final SoftwareModule softwareModule = testdataFactory.createSoftwareModuleOs();
|
||||
distributionSetManagement.assignSoftwareModules(distributionSet.getId(),
|
||||
Collections.singletonList(softwareModule.getId()));
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation(
|
||||
Collections.singletonList(distributionSet.getId()), CancelationType.NONE, false));
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception").isThrownBy(() -> distributionSetManagement
|
||||
.unassignSoftwareModule(distributionSet.getId(), softwareModule.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(allSpPermissions = true)
|
||||
@Description("Checks that metadata for a distribution set can be updated.")
|
||||
@@ -937,6 +985,24 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(distributionSetManagement.findByCompleted(PAGE, true).getTotalElements()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Deletes an invalid distribution set")
|
||||
public void deleteInvalidDistributionSet() {
|
||||
final DistributionSet set = testdataFactory.createAndInvalidateDistributionSet();
|
||||
assertThat(distributionSetRepository.findById(set.getId())).isNotEmpty();
|
||||
distributionSetManagement.delete(set.getId());
|
||||
assertThat(distributionSetRepository.findById(set.getId())).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Deletes an incomplete distribution set")
|
||||
public void deleteIncompleteDistributionSet() {
|
||||
final DistributionSet set = testdataFactory.createIncompleteDistributionSet();
|
||||
assertThat(distributionSetRepository.findById(set.getId())).isNotEmpty();
|
||||
distributionSetManagement.delete(set.getId());
|
||||
assertThat(distributionSetRepository.findById(set.getId())).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Queries and loads the metadata related to a given software module.")
|
||||
public void findAllDistributionSetMetadataByDsId() {
|
||||
@@ -1013,4 +1079,54 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(collect).containsAll(searchIds);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that an exception is thrown when trying to get an invalid distribution set")
|
||||
public void verifyGetValid() {
|
||||
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> distributionSetManagement.getValid(distributionSet.getId()));
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> distributionSetManagement.getValidAndComplete(distributionSet.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that an exception is thrown when trying to get an incomplete distribution set")
|
||||
public void verifyGetValidAndComplete() {
|
||||
final DistributionSet distributionSet = testdataFactory.createIncompleteDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.as("Incomplete distributionSet should throw an exception")
|
||||
.isThrownBy(() -> distributionSetManagement.getValidAndComplete(distributionSet.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that an exception is thrown when trying to create or update metadata for an invalid distribution set.")
|
||||
public void createMetadataForInvalidDistributionSet() {
|
||||
final String knownKey1 = "myKnownKey1";
|
||||
final String knownKey2 = "myKnownKey2";
|
||||
final String knownValue = "myKnownValue";
|
||||
final String knownUpdateValue = "knownUpdateValue";
|
||||
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
distributionSetManagement.createMetaData(ds.getId(),
|
||||
Collections.singletonList(entityFactory.generateDsMetadata(knownKey1, knownValue)));
|
||||
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(
|
||||
new DistributionSetInvalidation(Arrays.asList(ds.getId()), CancelationType.NONE, false));
|
||||
|
||||
// assert that no new metadata can be created
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> distributionSetManagement.createMetaData(ds.getId(),
|
||||
Collections.singletonList(entityFactory.generateDsMetadata(knownKey2, knownValue))));
|
||||
|
||||
// assert that an existing metadata can not be updated
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception").isThrownBy(() -> distributionSetManagement
|
||||
.updateMetaData(ds.getId(), entityFactory.generateDsMetadata(knownKey1, knownUpdateValue)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
@@ -72,7 +74,6 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -243,8 +244,9 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(firstGroup.getStatus()).isEqualTo(RolloutGroupStatus.RUNNING);
|
||||
|
||||
// verify other groups are scheduled
|
||||
final List<RolloutGroup> scheduledGroups = rolloutGroupManagement.findByRollout(
|
||||
new OffsetBasedPageRequest(1, 100, Sort.by(Direction.ASC, "id")), createdRollout.getId()).getContent();
|
||||
final List<RolloutGroup> scheduledGroups = rolloutGroupManagement
|
||||
.findByRollout(new OffsetBasedPageRequest(1, 100, Sort.by(Direction.ASC, "id")), createdRollout.getId())
|
||||
.getContent();
|
||||
scheduledGroups.forEach(group -> assertThat(group.getStatus()).isEqualTo(RolloutGroupStatus.SCHEDULED)
|
||||
.as("group which should be in scheduled state is in " + group.getStatus() + " state"));
|
||||
// verify that the first group actions has been started and are in state
|
||||
@@ -436,8 +438,9 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(errorGroup.get(0).getStatus()).isEqualTo(RolloutGroupStatus.ERROR);
|
||||
|
||||
// all other groups should still be in scheduled state
|
||||
final List<RolloutGroup> scheduleGroups = rolloutGroupManagement.findByRollout(
|
||||
new OffsetBasedPageRequest(1, 100, Sort.by(Direction.ASC, "id")), createdRollout.getId()).getContent();
|
||||
final List<RolloutGroup> scheduleGroups = rolloutGroupManagement
|
||||
.findByRollout(new OffsetBasedPageRequest(1, 100, Sort.by(Direction.ASC, "id")), createdRollout.getId())
|
||||
.getContent();
|
||||
scheduleGroups.forEach(group -> assertThat(group.getStatus()).isEqualTo(RolloutGroupStatus.SCHEDULED));
|
||||
}
|
||||
|
||||
@@ -470,8 +473,9 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(rollout.getStatus()).isEqualTo(RolloutStatus.PAUSED);
|
||||
|
||||
// all other groups should still be in scheduled state
|
||||
final List<RolloutGroup> scheduleGroups = rolloutGroupManagement.findByRollout(
|
||||
new OffsetBasedPageRequest(1, 100, Sort.by(Direction.ASC, "id")), createdRollout.getId()).getContent();
|
||||
final List<RolloutGroup> scheduleGroups = rolloutGroupManagement
|
||||
.findByRollout(new OffsetBasedPageRequest(1, 100, Sort.by(Direction.ASC, "id")), createdRollout.getId())
|
||||
.getContent();
|
||||
scheduleGroups.forEach(group -> assertThat(group.getStatus()).isEqualTo(RolloutGroupStatus.SCHEDULED));
|
||||
|
||||
// resume the rollout again after it gets paused by error action
|
||||
@@ -521,8 +525,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// verify all groups are in finished state
|
||||
rolloutGroupManagement
|
||||
.findByRollout(new OffsetBasedPageRequest(0, 100, Sort.by(Direction.ASC, "id")),
|
||||
createdRollout.getId())
|
||||
.findByRollout(new OffsetBasedPageRequest(0, 100, Sort.by(Direction.ASC, "id")), createdRollout.getId())
|
||||
.forEach(group -> assertThat(group.getStatus()).isEqualTo(RolloutGroupStatus.FINISHED));
|
||||
|
||||
// verify that rollout itself is in finished state
|
||||
@@ -1823,6 +1826,56 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(actions).allMatch(action -> !action.getWeight().isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to create a rollout with an invalidated distribution set.")
|
||||
public void createRolloutWithInvalidDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> testdataFactory.createRolloutByVariables("createRolloutWithInvalidDistributionSet",
|
||||
"desc", 2, "name==*", distributionSet, "50", "80"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to create a rollout with an incomplete distribution set.")
|
||||
public void createRolloutWithIncompleteDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createIncompleteDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.as("Incomplete distributionSet should throw an exception")
|
||||
.isThrownBy(() -> testdataFactory.createRolloutByVariables("createRolloutWithIncompleteDistributionSet",
|
||||
"desc", 2, "name==*", distributionSet, "50", "80"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to update a rollout with an invalidated distribution set.")
|
||||
public void updateRolloutWithInvalidDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
testdataFactory.createTarget();
|
||||
final Rollout rollout = testdataFactory.createRolloutByVariables("updateRolloutWithInvalidDistributionSet",
|
||||
"desc", 2, "name==*", distributionSet, "50", "80");
|
||||
final DistributionSet invalidDistributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception").isThrownBy(() -> rolloutManagement
|
||||
.update(entityFactory.rollout().update(rollout.getId()).set(invalidDistributionSet.getId())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to update a rollout with an incomplete distribution set.")
|
||||
public void updateRolloutWithIncompleteDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
testdataFactory.createTarget();
|
||||
final Rollout rollout = testdataFactory.createRolloutByVariables("updateRolloutWithIncompleteDistributionSet",
|
||||
"desc", 2, "name==*", distributionSet, "50", "80");
|
||||
final DistributionSet incompleteDistributionSet = testdataFactory.createIncompleteDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.as("Incomplete distributionSet should throw an exception").isThrownBy(() -> rolloutManagement.update(
|
||||
entityFactory.rollout().update(rollout.getId()).set(incompleteDistributionSet.getId())));
|
||||
}
|
||||
|
||||
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage,
|
||||
final String targetFilter) {
|
||||
return entityFactory.rolloutGroup().create().name("Group" + index).description("Group" + index + "desc")
|
||||
|
||||
@@ -23,14 +23,17 @@ import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -51,7 +54,7 @@ import io.qameta.allure.Story;
|
||||
|
||||
/**
|
||||
* Test class for {@link TargetFilterQueryManagement}.
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Feature("Component Tests - Repository")
|
||||
@Story("Target Filter Query Management")
|
||||
@@ -252,7 +255,7 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
.create(entityFactory.distributionSet().create().name("incomplete").version("1")
|
||||
.type(testdataFactory.findOrCreateDefaultTestDsType()));
|
||||
|
||||
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class)
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(incompleteDistributionSet.getId())));
|
||||
}
|
||||
@@ -263,7 +266,7 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
assignDistributionSet(softDeletedDs, testdataFactory.createTarget("forSoftDeletedDs"));
|
||||
distributionSetManagement.delete(softDeletedDs.getId());
|
||||
|
||||
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class)
|
||||
assertThatExceptionOfType(EntityNotFoundException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(softDeletedDs.getId())));
|
||||
}
|
||||
@@ -502,4 +505,60 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
assertThat(targetFilterQueryManagement.get(filterId).get().getAutoAssignWeight().get())
|
||||
.isEqualTo(Action.WEIGHT_MIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to create a target filter with an invalidated distribution set.")
|
||||
public void createTargetFilterWithInvalidDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("createTargetFilterWithInvalidDistributionSet")
|
||||
.query("name==*").autoAssignDistributionSet(distributionSet)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to create a target filter with an incomplete distribution set.")
|
||||
public void createTargetFilterWithIncompleteDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createIncompleteDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.as("Incomplete distributionSet should throw an exception")
|
||||
.isThrownBy(() -> targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
|
||||
.name("createTargetFilterWithIncompleteDistributionSet").query("name==*")
|
||||
.autoAssignDistributionSet(distributionSet)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to update a target filter with an invalidated distribution set.")
|
||||
public void updateAutoAssignDsWithInvalidDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("updateAutoAssignDsWithInvalidDistributionSet")
|
||||
.query("name==*").autoAssignDistributionSet(distributionSet));
|
||||
final DistributionSet invalidDistributionSet = testdataFactory.createAndInvalidateDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(InvalidDistributionSetException.class)
|
||||
.as("Invalid distributionSet should throw an exception")
|
||||
.isThrownBy(() -> targetFilterQueryManagement
|
||||
.updateAutoAssignDS(new AutoAssignDistributionSetUpdate(targetFilterQuery.getId())
|
||||
.ds(invalidDistributionSet.getId())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown when trying to update a target filter with an incomplete distribution set.")
|
||||
public void updateAutoAssignDsWithIncompleteDistributionSet() {
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("updateAutoAssignDsWithIncompleteDistributionSet")
|
||||
.query("name==*").autoAssignDistributionSet(distributionSet));
|
||||
final DistributionSet incompleteDistributionSet = testdataFactory.createIncompleteDistributionSet();
|
||||
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class)
|
||||
.as("Incomplete distributionSet should throw an exception")
|
||||
.isThrownBy(() -> targetFilterQueryManagement
|
||||
.updateAutoAssignDS(new AutoAssignDistributionSetUpdate(targetFilterQuery.getId())
|
||||
.ds(incompleteDistributionSet.getId())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -105,11 +105,11 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
||||
final DistributionSet setB = testdataFactory.createDistributionSet("dsB");
|
||||
|
||||
// target filter query that matches all targets
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("filterA").query("name==*")).getId())
|
||||
.ds(setA.getId()));
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.updateAutoAssignDS(entityFactory
|
||||
.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("filterA").query("name==*")).getId())
|
||||
.ds(setA.getId()));
|
||||
|
||||
final String targetDsAIdPref = "targ";
|
||||
final List<Target> targets = testdataFactory.createTargets(100, targetDsAIdPref,
|
||||
@@ -159,7 +159,7 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// target filter query that matches first bunch of targets, that should
|
||||
// fail
|
||||
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class).isThrownBy(() -> {
|
||||
assertThatExceptionOfType(IncompleteDistributionSetException.class).isThrownBy(() -> {
|
||||
final Long filterId = targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("filterA").query("id==" + targetDsFIdPref + "*"))
|
||||
.getId();
|
||||
@@ -221,10 +221,10 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
||||
final DistributionSet distributionSet, final List<Target> targets) {
|
||||
final Set<String> targetIds = targets.stream().map(Target::getControllerId).collect(Collectors.toSet());
|
||||
|
||||
actionRepository.findByDistributionSetId(Pageable.unpaged(), distributionSet.getId())
|
||||
.stream().filter(a -> targetIds.contains(a.getTarget().getControllerId()))
|
||||
.forEach(a -> assertThat(a.getInitiatedBy()).as(
|
||||
"Action should be initiated by the user who initiated the auto assignment")
|
||||
actionRepository.findByDistributionSetId(Pageable.unpaged(), distributionSet.getId()).stream()
|
||||
.filter(a -> targetIds.contains(a.getTarget().getControllerId()))
|
||||
.forEach(a -> assertThat(a.getInitiatedBy())
|
||||
.as("Action should be initiated by the user who initiated the auto assignment")
|
||||
.isEqualTo(targetFilterQuery.getAutoAssignInitiatedBy()));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user