Provide API for auto assignment check for specific device (#1262)
* Extend the auto assign executor to execute a auto assignment check for a specific device. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * add tests and handle exceptions Signed-off-by: Stefan Klotz <stefan.klotz@bosch.io> * add unit test Signed-off-by: Stefan Klotz <stefan.klotz@bosch.io> * add Copyright header Signed-off-by: Stefan Klotz <stefan.klotz@bosch.io> * fix Copyright header Signed-off-by: Stefan Klotz <stefan.klotz@bosch.io> * add authorization Signed-off-by: Stefan Klotz <stefan.klotz@bosch.io> * fix exception handling and authorization Signed-off-by: Stefan Klotz <stefan.klotz@bosch.io> * renaming Signed-off-by: Stefan Klotz <stefan.klotz@bosch.io> * Rename auto assignment functions Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> Co-authored-by: Stefan Klotz <stefan.klotz@bosch.io>
This commit is contained in:
@@ -800,6 +800,25 @@ public interface TargetManagement {
|
|||||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
boolean existsByControllerId(@NotEmpty String controllerId);
|
boolean existsByControllerId(@NotEmpty String controllerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify if a target matches a specific target filter query, does not have
|
||||||
|
* a specific DS already assigned and is compatible with it.
|
||||||
|
*
|
||||||
|
* @param controllerId
|
||||||
|
* of the {@link org.eclipse.hawkbit.repository.model.Target} to
|
||||||
|
* check
|
||||||
|
* @param distributionSetId
|
||||||
|
* of the
|
||||||
|
* {@link org.eclipse.hawkbit.repository.model.DistributionSet}
|
||||||
|
* to consider
|
||||||
|
* @param targetFilterQuery
|
||||||
|
* to execute
|
||||||
|
* @return true if it matches
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
|
||||||
|
boolean isTargetMatchingQueryAndDSNotAssignedAndCompatible(@NotNull String controllerId, long distributionSetId,
|
||||||
|
@NotNull String targetFilterQuery);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a list of target meta data entries.
|
* Creates a list of target meta data entries.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ package org.eclipse.hawkbit.repository.autoassign;
|
|||||||
* An interface declaration which contains the check for the auto assignment
|
* An interface declaration which contains the check for the auto assignment
|
||||||
* logic.
|
* logic.
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
|
||||||
public interface AutoAssignExecutor {
|
public interface AutoAssignExecutor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,6 +19,14 @@ public interface AutoAssignExecutor {
|
|||||||
* triggers the check and assignment to targets that don't have the design DS
|
* triggers the check and assignment to targets that don't have the design DS
|
||||||
* yet
|
* yet
|
||||||
*/
|
*/
|
||||||
void check();
|
void checkAllTargets();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method performs an auto assign check for a specific device only
|
||||||
|
*
|
||||||
|
* @param controllerId
|
||||||
|
* of the device to check
|
||||||
|
*/
|
||||||
|
void checkSingleTarget(String controllerId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.Collections;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
|||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
||||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
@@ -853,6 +855,25 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
return targetRepository.exists(TargetSpecifications.hasControllerId(controllerId));
|
return targetRepository.exists(TargetSpecifications.hasControllerId(controllerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatible(final String controllerId,
|
||||||
|
final long distributionSetId, final String targetFilterQuery) {
|
||||||
|
RSQLUtility.validateRsqlFor(targetFilterQuery, TargetFields.class);
|
||||||
|
final DistributionSet ds = distributionSetManagement.get(distributionSetId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, distributionSetId));
|
||||||
|
final Long distSetTypeId = ds.getType().getId();
|
||||||
|
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||||
|
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||||
|
database),
|
||||||
|
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||||
|
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId),
|
||||||
|
TargetSpecifications.hasControllerId(controllerId));
|
||||||
|
|
||||||
|
final Specification<JpaTarget> combinedSpecification = Objects
|
||||||
|
.requireNonNull(SpecificationsBuilder.combineWithAnd(specList));
|
||||||
|
return targetRepository.exists(combinedSpecification);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<Target> findByControllerAttributesRequested(final Pageable pageReq) {
|
public Page<Target> findByControllerAttributesRequested(final Pageable pageReq) {
|
||||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageReq,
|
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageReq,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.autoassign;
|
package org.eclipse.hawkbit.repository.jpa.autoassign;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -64,12 +65,21 @@ public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
public void check() {
|
public void checkAllTargets() {
|
||||||
LOGGER.debug("Auto assign check call for tenant {} started", getTenantAware().getCurrentTenant());
|
LOGGER.debug("Auto assign check call for tenant {} started", getTenantAware().getCurrentTenant());
|
||||||
forEachFilterWithAutoAssignDS(this::checkByTargetFilterQueryAndAssignDS);
|
forEachFilterWithAutoAssignDS(this::checkByTargetFilterQueryAndAssignDS);
|
||||||
LOGGER.debug("Auto assign check call for tenant {} finished", getTenantAware().getCurrentTenant());
|
LOGGER.debug("Auto assign check call for tenant {} finished", getTenantAware().getCurrentTenant());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkSingleTarget(String controllerId) {
|
||||||
|
LOGGER.debug("Auto assign check call for tenant {} and device {} started", getTenantAware().getCurrentTenant(),
|
||||||
|
controllerId);
|
||||||
|
forEachFilterWithAutoAssignDS(filter -> checkForDevice(controllerId, filter));
|
||||||
|
LOGGER.debug("Auto assign check call for tenant {} and device {} finished", getTenantAware().getCurrentTenant(),
|
||||||
|
controllerId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the distribution set, gets all controllerIds and assigns the DS
|
* Fetches the distribution set, gets all controllerIds and assigns the DS
|
||||||
* to them. Catches PersistenceException and own exceptions derived from
|
* to them. Catches PersistenceException and own exceptions derived from
|
||||||
@@ -104,4 +114,23 @@ public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
|||||||
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} finished",
|
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} finished",
|
||||||
getTenantAware().getCurrentTenant(), targetFilterQuery.getId());
|
getTenantAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkForDevice(final String controllerId, final TargetFilterQuery targetFilterQuery) {
|
||||||
|
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} for device {} started",
|
||||||
|
getTenantAware().getCurrentTenant(), targetFilterQuery.getId(), controllerId);
|
||||||
|
try {
|
||||||
|
final boolean controllerIdMatches = targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(
|
||||||
|
controllerId, targetFilterQuery.getAutoAssignDistributionSet().getId(),
|
||||||
|
targetFilterQuery.getQuery());
|
||||||
|
|
||||||
|
if (controllerIdMatches) {
|
||||||
|
runTransactionalAssignment(targetFilterQuery, Collections.singletonList(controllerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (final PersistenceException | AbstractServerRtException e) {
|
||||||
|
LOGGER.error("Error during auto assign check of target filter query id {}", targetFilterQuery.getId(), e);
|
||||||
|
}
|
||||||
|
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} finished",
|
||||||
|
getTenantAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class AutoAssignScheduler {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
LOGGER.debug("Auto assign scheduled execution has aquired lock and started for each tenant.");
|
LOGGER.debug("Auto assign scheduled execution has aquired lock and started for each tenant.");
|
||||||
systemManagement.forEachTenant(tenant -> autoAssignExecutor.check());
|
systemManagement.forEachTenant(tenant -> autoAssignExecutor.checkAllTargets());
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
LOGGER.debug("Auto assign scheduled execution has released lock and finished.");
|
LOGGER.debug("Auto assign scheduled execution has released lock and finished.");
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException
|
|||||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
|
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
|
||||||
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||||
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||||
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
|
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
|
||||||
@@ -1256,6 +1258,83 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
validateFoundTargetsByRsql(rsqlOrControllerIdNotEqualFilter, controllerId1, controllerId2);
|
validateFoundTargetsByRsql(rsqlOrControllerIdNotEqualFilter, controllerId1, controllerId2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Target matches filter.")
|
||||||
|
void matchesFilter() {
|
||||||
|
final Target target = createTargetWithMetadata("target1", 2);
|
||||||
|
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||||
|
final String filter = "metadata.key1==target1-value1";
|
||||||
|
|
||||||
|
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target.getControllerId(),
|
||||||
|
ds.getId(), filter)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Target does not matches filter.")
|
||||||
|
void matchesFilterWrongFilter() {
|
||||||
|
final Target target = testdataFactory.createTarget();
|
||||||
|
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||||
|
final String filter = "metadata.key==not_existing";
|
||||||
|
|
||||||
|
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target.getControllerId(),
|
||||||
|
ds.getId(), filter)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Target matches filter but DS already assigned.")
|
||||||
|
void matchesFilterDsAssigned() {
|
||||||
|
final Target target = testdataFactory.createTarget();
|
||||||
|
final DistributionSet ds1 = testdataFactory.createDistributionSet();
|
||||||
|
final DistributionSet ds2 = testdataFactory.createDistributionSet();
|
||||||
|
assignDistributionSet(ds1, target);
|
||||||
|
assignDistributionSet(ds2, target);
|
||||||
|
final String filter = "name==*";
|
||||||
|
|
||||||
|
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target.getControllerId(),
|
||||||
|
ds1.getId(), filter)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Target matches filter for DS with wrong type.")
|
||||||
|
void matchesFilterWrongType() {
|
||||||
|
final TargetType type = testdataFactory.createTargetType("type", Collections.emptyList());
|
||||||
|
final Target target = testdataFactory.createTarget("target", "target", type.getId());
|
||||||
|
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||||
|
|
||||||
|
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target.getControllerId(),
|
||||||
|
ds.getId(), "name==*")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Target matches filter that is invalid.")
|
||||||
|
void matchesFilterInvalidFilter() {
|
||||||
|
final String target = testdataFactory.createTarget().getControllerId();
|
||||||
|
final Long ds = testdataFactory.createDistributionSet().getId();
|
||||||
|
|
||||||
|
assertThatExceptionOfType(RSQLParameterSyntaxException.class).isThrownBy(() -> targetManagement
|
||||||
|
.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, "invalid_syntax"));
|
||||||
|
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class).isThrownBy(() -> targetManagement
|
||||||
|
.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, "invalid_field==1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Target matches filter for not existing target.")
|
||||||
|
void matchesFilterTargetNotExists() {
|
||||||
|
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||||
|
|
||||||
|
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible("notExisting", ds.getId(),
|
||||||
|
"name==*")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Target matches filter for not existing DS.")
|
||||||
|
void matchesFilterDsNotExists() {
|
||||||
|
final String target = testdataFactory.createTarget().getControllerId();
|
||||||
|
|
||||||
|
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
|
||||||
|
() -> targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, 123, "name==*"));
|
||||||
|
}
|
||||||
|
|
||||||
private void validateFoundTargetsByRsql(final String rsqlFilter, final String... controllerIds) {
|
private void validateFoundTargetsByRsql(final String rsqlFilter, final String... controllerIds) {
|
||||||
final Slice<Target> foundTargetsByMetadataAndControllerId = targetManagement.findByRsql(PAGE, rsqlFilter);
|
final Slice<Target> foundTargetsByMetadataAndControllerId = targetManagement.findByRsql(PAGE, rsqlFilter);
|
||||||
final long foundTargetsByMetadataAndControllerIdCount = targetManagement.countByRsql(rsqlFilter);
|
final long foundTargetsByMetadataAndControllerIdCount = targetManagement.countByRsql(rsqlFilter);
|
||||||
|
|||||||
@@ -0,0 +1,411 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.repository.jpa.autoassign;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||||
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
|
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||||
|
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
|
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Slice;
|
||||||
|
|
||||||
|
import io.qameta.allure.Description;
|
||||||
|
import io.qameta.allure.Feature;
|
||||||
|
import io.qameta.allure.Step;
|
||||||
|
import io.qameta.allure.Story;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for {@link AutoAssignChecker}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Feature("Component Tests - Repository")
|
||||||
|
@Story("Auto assign checker")
|
||||||
|
class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AutoAssignChecker autoAssignChecker;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActionRepository actionRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verifies that a running action is auto canceled by a AutoAssignment which assigns another distribution-set.")
|
||||||
|
void autoAssignDistributionSetAndAutoCloseOldActions() {
|
||||||
|
|
||||||
|
tenantConfigurationManagement
|
||||||
|
.addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String knownControllerId = "controller12345";
|
||||||
|
final DistributionSet firstDistributionSet = testdataFactory.createDistributionSet();
|
||||||
|
final DistributionSet secondDistributionSet = testdataFactory.createDistributionSet("second");
|
||||||
|
testdataFactory.createTarget(knownControllerId);
|
||||||
|
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(firstDistributionSet.getId(),
|
||||||
|
knownControllerId);
|
||||||
|
final Long manuallyAssignedActionId = getFirstAssignedActionId(assignmentResult);
|
||||||
|
|
||||||
|
// target filter query that matches all targets
|
||||||
|
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
||||||
|
.create(entityFactory.targetFilterQuery().create().name("filterA").query("name==*"));
|
||||||
|
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||||
|
.updateAutoAssign(targetFilterQuery.getId()).ds(secondDistributionSet.getId()));
|
||||||
|
// Run the check
|
||||||
|
autoAssignChecker.checkAllTargets();
|
||||||
|
|
||||||
|
// verify that manually created action is canceled and action
|
||||||
|
// created from AutoAssign is running
|
||||||
|
final List<Action> actionsByKnownTarget = deploymentManagement.findActionsByTarget(knownControllerId, PAGE)
|
||||||
|
.getContent();
|
||||||
|
// should be 2 actions, one manually and one from the AutoAssign
|
||||||
|
assertThat(actionsByKnownTarget).hasSize(2);
|
||||||
|
// verify that manually assigned action is still running
|
||||||
|
assertThat(deploymentManagement.findAction(manuallyAssignedActionId).get().getStatus())
|
||||||
|
.isEqualTo(Status.CANCELED);
|
||||||
|
// verify that AutoAssign created action is running
|
||||||
|
final Action rolloutCreatedAction = actionsByKnownTarget.stream()
|
||||||
|
.filter(action -> !action.getId().equals(manuallyAssignedActionId)).findAny().get();
|
||||||
|
assertThat(rolloutCreatedAction.getStatus()).isEqualTo(Status.RUNNING);
|
||||||
|
assertThat(rolloutCreatedAction.getActionType()).isEqualTo(ActionType.FORCED);
|
||||||
|
} finally {
|
||||||
|
tenantConfigurationManagement
|
||||||
|
.addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Test auto assignment of a DS to filtered targets")
|
||||||
|
void checkAutoAssign() {
|
||||||
|
|
||||||
|
final DistributionSet setA = testdataFactory.createDistributionSet("dsA"); // will
|
||||||
|
// be
|
||||||
|
// auto
|
||||||
|
// assigned
|
||||||
|
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 String targetDsAIdPref = "targ";
|
||||||
|
final List<Target> targets = testdataFactory.createTargets(25, targetDsAIdPref,
|
||||||
|
targetDsAIdPref.concat(" description"));
|
||||||
|
final int targetsCount = targets.size();
|
||||||
|
|
||||||
|
// assign set A to first 10 targets
|
||||||
|
assignDistributionSet(setA, targets.subList(0, 10));
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(setA, targets.subList(0, 10), targetsCount);
|
||||||
|
|
||||||
|
// assign set B to first 5 targets
|
||||||
|
// they have now 2 DS in their action history and should not get updated
|
||||||
|
// with dsA
|
||||||
|
assignDistributionSet(setB, targets.subList(0, 5));
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(setB, targets.subList(0, 5), targetsCount);
|
||||||
|
|
||||||
|
// assign set B to next 10 targets
|
||||||
|
assignDistributionSet(setB, targets.subList(10, 20));
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(setB, targets.subList(10, 20), targetsCount);
|
||||||
|
|
||||||
|
// Count the number of targets that will be assigned with setA
|
||||||
|
assertThat(targetManagement.countByRsqlAndNonDSAndCompatible(setA.getId(), targetFilterQuery.getQuery()))
|
||||||
|
.isEqualTo(15);
|
||||||
|
|
||||||
|
// Run the check
|
||||||
|
autoAssignChecker.checkAllTargets();
|
||||||
|
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(setA, targets.subList(5, 25), targetsCount);
|
||||||
|
|
||||||
|
// first 5 should keep their dsB, because they already had the dsA once
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(setB, targets.subList(0, 5), targetsCount);
|
||||||
|
|
||||||
|
verifyThatCreatedActionsAreInitiatedByCurrentUser(targetFilterQuery, setA, targets);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Test auto assignment of a DS for a specific device")
|
||||||
|
void checkAutoAssignmentForDevice() {
|
||||||
|
|
||||||
|
final DistributionSet toAssignDs = testdataFactory.createDistributionSet();
|
||||||
|
|
||||||
|
// target filter query that matches all targets
|
||||||
|
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||||
|
.updateAutoAssign(targetFilterQueryManagement
|
||||||
|
.create(entityFactory.targetFilterQuery().create().name("filterA").query("name==*")).getId())
|
||||||
|
.ds(toAssignDs.getId()));
|
||||||
|
|
||||||
|
final List<Target> targets = testdataFactory.createTargets(25);
|
||||||
|
final int targetsCount = targets.size();
|
||||||
|
|
||||||
|
// Run the check
|
||||||
|
autoAssignChecker.checkSingleTarget(targets.get(0).getControllerId());
|
||||||
|
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(toAssignDs, targets.subList(0, 1), targetsCount);
|
||||||
|
|
||||||
|
verifyThatTargetsNotHaveDistributionSetAssignment(toAssignDs, targets.subList(1, 25));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Test auto assignment of an incomplete DS to filtered targets, that causes failures")
|
||||||
|
void checkAutoAssignWithFailures() {
|
||||||
|
|
||||||
|
// incomplete distribution set that will be assigned
|
||||||
|
final DistributionSet setF = distributionSetManagement.create(entityFactory.distributionSet().create()
|
||||||
|
.name("dsA").version("1").type(testdataFactory.findOrCreateDefaultTestDsType()));
|
||||||
|
final DistributionSet setA = testdataFactory.createDistributionSet("dsA");
|
||||||
|
final DistributionSet setB = testdataFactory.createDistributionSet("dsB");
|
||||||
|
|
||||||
|
final String targetDsAIdPref = "targA";
|
||||||
|
final String targetDsFIdPref = "targB";
|
||||||
|
|
||||||
|
// target filter query that matches first bunch of targets, that should
|
||||||
|
// fail
|
||||||
|
assertThatExceptionOfType(IncompleteDistributionSetException.class).isThrownBy(() -> {
|
||||||
|
final Long filterId = targetFilterQueryManagement.create(
|
||||||
|
entityFactory.targetFilterQuery().create().name("filterA").query("id==" + targetDsFIdPref + "*"))
|
||||||
|
.getId();
|
||||||
|
targetFilterQueryManagement
|
||||||
|
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(setF.getId()));
|
||||||
|
});
|
||||||
|
// target filter query that matches failed bunch of targets
|
||||||
|
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("filterB")
|
||||||
|
.query("id==" + targetDsAIdPref + "*").autoAssignDistributionSet(setA.getId()));
|
||||||
|
|
||||||
|
final List<Target> targetsF = testdataFactory.createTargets(10, targetDsFIdPref,
|
||||||
|
targetDsFIdPref.concat(" description"));
|
||||||
|
|
||||||
|
final List<Target> targetsA = testdataFactory.createTargets(10, targetDsAIdPref,
|
||||||
|
targetDsAIdPref.concat(" description"));
|
||||||
|
|
||||||
|
final int targetsCount = targetsA.size() + targetsF.size();
|
||||||
|
|
||||||
|
// assign set B to first 5 targets of fail group
|
||||||
|
assignDistributionSet(setB, targetsF.subList(0, 5));
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(setB, targetsF.subList(0, 5), targetsCount);
|
||||||
|
|
||||||
|
// Run the check
|
||||||
|
autoAssignChecker.checkAllTargets();
|
||||||
|
|
||||||
|
// first 5 targets of the fail group should still have setB
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(setB, targetsF.subList(0, 5), targetsCount);
|
||||||
|
|
||||||
|
// all targets of A group should have received setA
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(setA, targetsA, targetsCount);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param set
|
||||||
|
* the expected distribution set
|
||||||
|
* @param targets
|
||||||
|
* the targets that should have it
|
||||||
|
*/
|
||||||
|
@Step
|
||||||
|
private void verifyThatTargetsHaveDistributionSetAssignment(final DistributionSet set, final List<Target> targets,
|
||||||
|
final int count) {
|
||||||
|
final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList());
|
||||||
|
|
||||||
|
final Slice<Target> targetsAll = targetManagement.findAll(PAGE);
|
||||||
|
assertThat(targetsAll).as("Count of targets").hasSize(count);
|
||||||
|
|
||||||
|
for (final Target target : targetsAll) {
|
||||||
|
if (targetIds.contains(target.getId())) {
|
||||||
|
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId()).get())
|
||||||
|
.as("assigned DS").isEqualTo(set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private void verifyThatTargetsNotHaveDistributionSetAssignment(final DistributionSet set,
|
||||||
|
final List<Target> targets) {
|
||||||
|
final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList());
|
||||||
|
|
||||||
|
final Slice<Target> targetsAll = targetManagement.findAll(PAGE);
|
||||||
|
|
||||||
|
for (final Target target : targetsAll) {
|
||||||
|
if (targetIds.contains(target.getId())) {
|
||||||
|
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId())).isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private void verifyThatCreatedActionsAreInitiatedByCurrentUser(final TargetFilterQuery targetFilterQuery,
|
||||||
|
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")
|
||||||
|
.isEqualTo(targetFilterQuery.getAutoAssignInitiatedBy()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Test auto assignment of a distribution set with FORCED, SOFT and DOWNLOAD_ONLY action types")
|
||||||
|
void checkAutoAssignWithDifferentActionTypes() {
|
||||||
|
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||||
|
final String targetDsAIdPref = "A";
|
||||||
|
final String targetDsBIdPref = "B";
|
||||||
|
final String targetDsCIdPref = "C";
|
||||||
|
|
||||||
|
final List<Target> targetsA = createTargetsAndAutoAssignDistSet(targetDsAIdPref, 5, distributionSet,
|
||||||
|
ActionType.FORCED);
|
||||||
|
final List<Target> targetsB = createTargetsAndAutoAssignDistSet(targetDsBIdPref, 10, distributionSet,
|
||||||
|
ActionType.SOFT);
|
||||||
|
final List<Target> targetsC = createTargetsAndAutoAssignDistSet(targetDsCIdPref, 10, distributionSet,
|
||||||
|
ActionType.DOWNLOAD_ONLY);
|
||||||
|
|
||||||
|
final int targetsCount = targetsA.size() + targetsB.size() + targetsC.size();
|
||||||
|
|
||||||
|
autoAssignChecker.checkAllTargets();
|
||||||
|
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(distributionSet, targetsA, targetsCount);
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(distributionSet, targetsB, targetsCount);
|
||||||
|
verifyThatTargetsHaveDistributionSetAssignment(distributionSet, targetsC, targetsCount);
|
||||||
|
|
||||||
|
verifyThatTargetsHaveAssignmentActionType(ActionType.FORCED, targetsA);
|
||||||
|
verifyThatTargetsHaveAssignmentActionType(ActionType.SOFT, targetsB);
|
||||||
|
verifyThatTargetsHaveAssignmentActionType(ActionType.DOWNLOAD_ONLY, targetsC);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private List<Target> createTargetsAndAutoAssignDistSet(final String prefix, final int targetCount,
|
||||||
|
final DistributionSet distributionSet, final ActionType actionType) {
|
||||||
|
|
||||||
|
final List<Target> targets = testdataFactory.createTargets(targetCount, "target" + prefix,
|
||||||
|
prefix.concat(" description"));
|
||||||
|
targetFilterQueryManagement.create(
|
||||||
|
entityFactory.targetFilterQuery().create().name("filter" + prefix).query("id==target" + prefix + "*")
|
||||||
|
.autoAssignDistributionSet(distributionSet).autoAssignActionType(actionType));
|
||||||
|
|
||||||
|
return targets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private void verifyThatTargetsHaveAssignmentActionType(final ActionType actionType, final List<Target> targets) {
|
||||||
|
final List<Action> actions = targets.stream().map(Target::getControllerId).flatMap(
|
||||||
|
controllerId -> deploymentManagement.findActionsByTarget(controllerId, PAGE).getContent().stream())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
assertThat(actions).hasSize(targets.size());
|
||||||
|
assertThat(actions).allMatch(action -> action.getActionType().equals(actionType));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("An auto assignment target filter with weight creates actions with weights")
|
||||||
|
void actionsWithWeightAreCreated() throws Exception {
|
||||||
|
final int amountOfTargets = 5;
|
||||||
|
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||||
|
final int weight = 32;
|
||||||
|
enableMultiAssignments();
|
||||||
|
|
||||||
|
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")
|
||||||
|
.autoAssignDistributionSet(ds).autoAssignWeight(weight));
|
||||||
|
testdataFactory.createTargets(amountOfTargets);
|
||||||
|
autoAssignChecker.checkAllTargets();
|
||||||
|
|
||||||
|
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
||||||
|
assertThat(actions).hasSize(amountOfTargets);
|
||||||
|
assertThat(actions).allMatch(action -> action.getWeight().get() == weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("An auto assignment target filter without weight still works after multi assignment is enabled")
|
||||||
|
void filterWithoutWeightWorksInMultiAssignmentMode() throws Exception {
|
||||||
|
final int amountOfTargets = 5;
|
||||||
|
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||||
|
targetFilterQueryManagement.create(
|
||||||
|
entityFactory.targetFilterQuery().create().name("a").query("name==*").autoAssignDistributionSet(ds));
|
||||||
|
enableMultiAssignments();
|
||||||
|
|
||||||
|
testdataFactory.createTargets(amountOfTargets);
|
||||||
|
autoAssignChecker.checkAllTargets();
|
||||||
|
|
||||||
|
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
||||||
|
assertThat(actions).hasSize(amountOfTargets);
|
||||||
|
assertThat(actions).allMatch(action -> !action.getWeight().isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verifies an auto assignment only creates actions for compatible targets")
|
||||||
|
void checkAutoAssignmentWithIncompatibleTargets() {
|
||||||
|
final int TARGET_COUNT = 5;
|
||||||
|
|
||||||
|
final DistributionSet testDs = testdataFactory.createDistributionSet();
|
||||||
|
final DistributionSetType incompatibleDsType1 = testdataFactory
|
||||||
|
.findOrCreateDistributionSetType("incompatibleDsType1", "incompDsType1");
|
||||||
|
final DistributionSetType incompatibleDsType2 = testdataFactory
|
||||||
|
.findOrCreateDistributionSetType("incompatibleDsType2", "incompDsType2");
|
||||||
|
final TargetFilterQuery testFilter = targetFilterQueryManagement.create(entityFactory.targetFilterQuery()
|
||||||
|
.create().name("test-filter").query("name==*").autoAssignDistributionSet(testDs));
|
||||||
|
|
||||||
|
final TargetType incompatibleEmptyType = testdataFactory.createTargetType("incompatibleEmptyType",
|
||||||
|
Collections.emptyList());
|
||||||
|
final TargetType incompatibleSingleType = testdataFactory.createTargetType("incompatibleSingleType",
|
||||||
|
Collections.singletonList(incompatibleDsType1));
|
||||||
|
final TargetType incompatibleMultiType = testdataFactory.createTargetType("incompatibleMultiType",
|
||||||
|
Arrays.asList(incompatibleDsType1, incompatibleDsType2));
|
||||||
|
final TargetType compatibleSingleType = testdataFactory.createTargetType("compatibleSingleType",
|
||||||
|
Collections.singletonList(testDs.getType()));
|
||||||
|
final TargetType compatibleMultiType = testdataFactory.createTargetType("compatibleMultiType",
|
||||||
|
Arrays.asList(testDs.getType(), incompatibleDsType1));
|
||||||
|
|
||||||
|
testdataFactory.createTargetsWithType(TARGET_COUNT, "incompatibleEmpty", incompatibleEmptyType);
|
||||||
|
testdataFactory.createTargetsWithType(TARGET_COUNT, "incompatibleSingle", incompatibleSingleType);
|
||||||
|
testdataFactory.createTargetsWithType(TARGET_COUNT, "incompatibleMulti", incompatibleMultiType);
|
||||||
|
|
||||||
|
final List<Target> compatibleTargetsSingleType = testdataFactory.createTargetsWithType(TARGET_COUNT,
|
||||||
|
"compatibleSingle", compatibleSingleType);
|
||||||
|
final List<Target> compatibleTargetsMultiType = testdataFactory.createTargetsWithType(TARGET_COUNT,
|
||||||
|
"compatibleMulti", compatibleMultiType);
|
||||||
|
final List<Target> compatibleTargetsWithoutType = testdataFactory.createTargets(TARGET_COUNT,
|
||||||
|
"compatibleSingleWithoutType");
|
||||||
|
|
||||||
|
final List<Long> compatibleTargets = Stream
|
||||||
|
.of(compatibleTargetsSingleType, compatibleTargetsMultiType, compatibleTargetsWithoutType)
|
||||||
|
.flatMap(Collection::stream).map(Target::getId).collect(Collectors.toList());
|
||||||
|
final long compatibleCount = targetManagement.countByRsqlAndNonDSAndCompatible(testDs.getId(),
|
||||||
|
testFilter.getQuery());
|
||||||
|
assertThat(compatibleCount).isEqualTo(compatibleTargets.size());
|
||||||
|
|
||||||
|
autoAssignChecker.checkAllTargets();
|
||||||
|
|
||||||
|
final List<Action> actions = deploymentManagement.findActionsAll(Pageable.unpaged()).getContent();
|
||||||
|
assertThat(actions).hasSize(compatibleTargets.size());
|
||||||
|
final List<Long> actionTargets = actions.stream().map(a -> a.getTarget().getId()).collect(Collectors.toList());
|
||||||
|
assertThat(actionTargets).containsExactlyInAnyOrderElementsOf(compatibleTargets);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||||
*
|
*
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
@@ -8,366 +8,113 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.autoassign;
|
package org.eclipse.hawkbit.repository.jpa.autoassign;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||||
import org.eclipse.hawkbit.repository.jpa.ActionRepository;
|
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
||||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
|
||||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.mockito.ArgumentMatcher;
|
||||||
import org.springframework.data.domain.Slice;
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.data.domain.SliceImpl;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
import io.qameta.allure.Description;
|
import io.qameta.allure.Description;
|
||||||
import io.qameta.allure.Feature;
|
import io.qameta.allure.Feature;
|
||||||
import io.qameta.allure.Step;
|
|
||||||
import io.qameta.allure.Story;
|
import io.qameta.allure.Story;
|
||||||
|
|
||||||
/**
|
@Feature("Unit Tests - Repository")
|
||||||
* Test class for {@link AutoAssignChecker}.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Feature("Component Tests - Repository")
|
|
||||||
@Story("Auto assign checker")
|
@Story("Auto assign checker")
|
||||||
class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class AutoAssignCheckerTest {
|
||||||
|
@Mock
|
||||||
|
private TargetFilterQueryManagement targetFilterQueryManagement;
|
||||||
|
@Mock
|
||||||
|
private TargetManagement targetManagement;
|
||||||
|
@Mock
|
||||||
|
private DeploymentManagement deploymentManagement;
|
||||||
|
@Mock
|
||||||
|
private PlatformTransactionManager transactionManager;
|
||||||
|
@Mock
|
||||||
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
@Autowired
|
private AutoAssignChecker sut;
|
||||||
private AutoAssignChecker autoAssignChecker;
|
|
||||||
|
|
||||||
@Autowired
|
@BeforeEach
|
||||||
private ActionRepository actionRepository;
|
void before() {
|
||||||
|
sut = new AutoAssignChecker(targetFilterQueryManagement, targetManagement, deploymentManagement,
|
||||||
@Test
|
transactionManager, tenantAware);
|
||||||
@Description("Verifies that a running action is auto canceled by a AutoAssignment which assigns another distribution-set.")
|
|
||||||
void autoAssignDistributionSetAndAutoCloseOldActions() {
|
|
||||||
|
|
||||||
tenantConfigurationManagement
|
|
||||||
.addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final String knownControllerId = "controller12345";
|
|
||||||
final DistributionSet firstDistributionSet = testdataFactory.createDistributionSet();
|
|
||||||
final DistributionSet secondDistributionSet = testdataFactory.createDistributionSet("second");
|
|
||||||
testdataFactory.createTarget(knownControllerId);
|
|
||||||
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(firstDistributionSet.getId(),
|
|
||||||
knownControllerId);
|
|
||||||
final Long manuallyAssignedActionId = getFirstAssignedActionId(assignmentResult);
|
|
||||||
|
|
||||||
// target filter query that matches all targets
|
|
||||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
|
||||||
.create(entityFactory.targetFilterQuery().create().name("filterA").query("name==*"));
|
|
||||||
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
|
||||||
.updateAutoAssign(targetFilterQuery.getId()).ds(secondDistributionSet.getId()));
|
|
||||||
// Run the check
|
|
||||||
autoAssignChecker.check();
|
|
||||||
|
|
||||||
// verify that manually created action is canceled and action
|
|
||||||
// created from AutoAssign is running
|
|
||||||
final List<Action> actionsByKnownTarget = deploymentManagement.findActionsByTarget(knownControllerId, PAGE)
|
|
||||||
.getContent();
|
|
||||||
// should be 2 actions, one manually and one from the AutoAssign
|
|
||||||
assertThat(actionsByKnownTarget).hasSize(2);
|
|
||||||
// verify that manually assigned action is still running
|
|
||||||
assertThat(deploymentManagement.findAction(manuallyAssignedActionId).get().getStatus())
|
|
||||||
.isEqualTo(Status.CANCELED);
|
|
||||||
// verify that AutoAssign created action is running
|
|
||||||
final Action rolloutCreatedAction = actionsByKnownTarget.stream()
|
|
||||||
.filter(action -> !action.getId().equals(manuallyAssignedActionId)).findAny().get();
|
|
||||||
assertThat(rolloutCreatedAction.getStatus()).isEqualTo(Status.RUNNING);
|
|
||||||
assertThat(rolloutCreatedAction.getActionType()).isEqualTo(ActionType.FORCED);
|
|
||||||
} finally {
|
|
||||||
tenantConfigurationManagement
|
|
||||||
.addOrUpdateConfiguration(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Test auto assignment of a DS to filtered targets")
|
@Description("Single device check triggers update for matching auto assignment filter.")
|
||||||
void checkAutoAssign() {
|
void checkForDevice() {
|
||||||
|
mockRunningAsNonSystem();
|
||||||
|
final String target = getRandomString();
|
||||||
|
final long ds = getRandomLong();
|
||||||
|
final TargetFilterQuery matching = mockFilterQuery(ds);
|
||||||
|
final TargetFilterQuery notMatching = mockFilterQuery(ds);
|
||||||
|
when(targetFilterQueryManagement.findWithAutoAssignDS(any()))
|
||||||
|
.thenReturn(new SliceImpl<>(Arrays.asList(notMatching, matching)));
|
||||||
|
|
||||||
final DistributionSet setA = testdataFactory.createDistributionSet("dsA"); // will
|
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, matching.getQuery()))
|
||||||
// be
|
.thenReturn(true);
|
||||||
// auto
|
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds,
|
||||||
// assigned
|
notMatching.getQuery())).thenReturn(false);
|
||||||
final DistributionSet setB = testdataFactory.createDistributionSet("dsB");
|
|
||||||
|
|
||||||
// target filter query that matches all targets
|
sut.checkSingleTarget(target);
|
||||||
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";
|
verify(deploymentManagement).assignDistributionSets(eq(matching.getAutoAssignInitiatedBy()),
|
||||||
final List<Target> targets = testdataFactory.createTargets(25, targetDsAIdPref,
|
Mockito.argThat(deployReqMatcher(target, ds)), any());
|
||||||
targetDsAIdPref.concat(" description"));
|
Mockito.verifyNoMoreInteractions(deploymentManagement);
|
||||||
final int targetsCount = targets.size();
|
|
||||||
|
|
||||||
// assign set A to first 10 targets
|
|
||||||
assignDistributionSet(setA, targets.subList(0, 10));
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(setA, targets.subList(0, 10), targetsCount);
|
|
||||||
|
|
||||||
// assign set B to first 5 targets
|
|
||||||
// they have now 2 DS in their action history and should not get updated
|
|
||||||
// with dsA
|
|
||||||
assignDistributionSet(setB, targets.subList(0, 5));
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(setB, targets.subList(0, 5), targetsCount);
|
|
||||||
|
|
||||||
// assign set B to next 10 targets
|
|
||||||
assignDistributionSet(setB, targets.subList(10, 20));
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(setB, targets.subList(10, 20), targetsCount);
|
|
||||||
|
|
||||||
// Count the number of targets that will be assigned with setA
|
|
||||||
assertThat(targetManagement.countByRsqlAndNonDSAndCompatible(setA.getId(), targetFilterQuery.getQuery()))
|
|
||||||
.isEqualTo(15);
|
|
||||||
|
|
||||||
// Run the check
|
|
||||||
autoAssignChecker.check();
|
|
||||||
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(setA, targets.subList(5, 25), targetsCount);
|
|
||||||
|
|
||||||
// first 5 should keep their dsB, because they already had the dsA once
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(setB, targets.subList(0, 5), targetsCount);
|
|
||||||
|
|
||||||
verifyThatCreatedActionsAreInitiatedByCurrentUser(targetFilterQuery, setA, targets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private ArgumentMatcher<List<DeploymentRequest>> deployReqMatcher(final String target, final long ds) {
|
||||||
@Description("Test auto assignment of an incomplete DS to filtered targets, that causes failures")
|
return requests -> {
|
||||||
void checkAutoAssignWithFailures() {
|
final DeploymentRequest request = requests.get(0);
|
||||||
|
return requests.size() == 1 && request.getDistributionSetId() == ds && request.getControllerId() == target;
|
||||||
// incomplete distribution set that will be assigned
|
};
|
||||||
final DistributionSet setF = distributionSetManagement.create(entityFactory.distributionSet().create()
|
|
||||||
.name("dsA").version("1").type(testdataFactory.findOrCreateDefaultTestDsType()));
|
|
||||||
final DistributionSet setA = testdataFactory.createDistributionSet("dsA");
|
|
||||||
final DistributionSet setB = testdataFactory.createDistributionSet("dsB");
|
|
||||||
|
|
||||||
final String targetDsAIdPref = "targA";
|
|
||||||
final String targetDsFIdPref = "targB";
|
|
||||||
|
|
||||||
// target filter query that matches first bunch of targets, that should
|
|
||||||
// fail
|
|
||||||
assertThatExceptionOfType(IncompleteDistributionSetException.class).isThrownBy(() -> {
|
|
||||||
final Long filterId = targetFilterQueryManagement.create(
|
|
||||||
entityFactory.targetFilterQuery().create().name("filterA").query("id==" + targetDsFIdPref + "*"))
|
|
||||||
.getId();
|
|
||||||
targetFilterQueryManagement
|
|
||||||
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(setF.getId()));
|
|
||||||
});
|
|
||||||
// target filter query that matches failed bunch of targets
|
|
||||||
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("filterB")
|
|
||||||
.query("id==" + targetDsAIdPref + "*").autoAssignDistributionSet(setA.getId()));
|
|
||||||
|
|
||||||
final List<Target> targetsF = testdataFactory.createTargets(10, targetDsFIdPref,
|
|
||||||
targetDsFIdPref.concat(" description"));
|
|
||||||
|
|
||||||
final List<Target> targetsA = testdataFactory.createTargets(10, targetDsAIdPref,
|
|
||||||
targetDsAIdPref.concat(" description"));
|
|
||||||
|
|
||||||
final int targetsCount = targetsA.size() + targetsF.size();
|
|
||||||
|
|
||||||
// assign set B to first 5 targets of fail group
|
|
||||||
assignDistributionSet(setB, targetsF.subList(0, 5));
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(setB, targetsF.subList(0, 5), targetsCount);
|
|
||||||
|
|
||||||
// Run the check
|
|
||||||
autoAssignChecker.check();
|
|
||||||
|
|
||||||
// first 5 targets of the fail group should still have setB
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(setB, targetsF.subList(0, 5), targetsCount);
|
|
||||||
|
|
||||||
// all targets of A group should have received setA
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(setA, targetsA, targetsCount);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static TargetFilterQuery mockFilterQuery(final long dsId) {
|
||||||
* @param set
|
final DistributionSet ds = mock(DistributionSet.class);
|
||||||
* the expected distribution set
|
when(ds.getId()).thenReturn(dsId);
|
||||||
* @param targets
|
final TargetFilterQuery filter = mock(TargetFilterQuery.class);
|
||||||
* the targets that should have it
|
when(filter.getId()).thenReturn(getRandomLong());
|
||||||
*/
|
when(filter.getQuery()).thenReturn(getRandomString());
|
||||||
@Step
|
lenient().when(filter.getAutoAssignInitiatedBy()).thenReturn(getRandomString());
|
||||||
private void verifyThatTargetsHaveDistributionSetAssignment(final DistributionSet set, final List<Target> targets,
|
when(filter.getAutoAssignDistributionSet()).thenReturn(ds);
|
||||||
final int count) {
|
return filter;
|
||||||
final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList());
|
|
||||||
|
|
||||||
final Slice<Target> targetsAll = targetManagement.findAll(PAGE);
|
|
||||||
assertThat(targetsAll).as("Count of targets").hasSize(count);
|
|
||||||
|
|
||||||
for (final Target target : targetsAll) {
|
|
||||||
if (targetIds.contains(target.getId())) {
|
|
||||||
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId()).get())
|
|
||||||
.as("assigned DS").isEqualTo(set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Step
|
private void mockRunningAsNonSystem() {
|
||||||
private void verifyThatCreatedActionsAreInitiatedByCurrentUser(final TargetFilterQuery targetFilterQuery,
|
when(tenantAware.getCurrentUsername()).thenReturn(getRandomString());
|
||||||
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")
|
|
||||||
.isEqualTo(targetFilterQuery.getAutoAssignInitiatedBy()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private static long getRandomLong() {
|
||||||
@Description("Test auto assignment of a distribution set with FORCED, SOFT and DOWNLOAD_ONLY action types")
|
return ThreadLocalRandom.current().nextLong();
|
||||||
void checkAutoAssignWithDifferentActionTypes() {
|
|
||||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
|
||||||
final String targetDsAIdPref = "A";
|
|
||||||
final String targetDsBIdPref = "B";
|
|
||||||
final String targetDsCIdPref = "C";
|
|
||||||
|
|
||||||
final List<Target> targetsA = createTargetsAndAutoAssignDistSet(targetDsAIdPref, 5, distributionSet,
|
|
||||||
ActionType.FORCED);
|
|
||||||
final List<Target> targetsB = createTargetsAndAutoAssignDistSet(targetDsBIdPref, 10, distributionSet,
|
|
||||||
ActionType.SOFT);
|
|
||||||
final List<Target> targetsC = createTargetsAndAutoAssignDistSet(targetDsCIdPref, 10, distributionSet,
|
|
||||||
ActionType.DOWNLOAD_ONLY);
|
|
||||||
|
|
||||||
final int targetsCount = targetsA.size() + targetsB.size() + targetsC.size();
|
|
||||||
|
|
||||||
autoAssignChecker.check();
|
|
||||||
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(distributionSet, targetsA, targetsCount);
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(distributionSet, targetsB, targetsCount);
|
|
||||||
verifyThatTargetsHaveDistributionSetAssignment(distributionSet, targetsC, targetsCount);
|
|
||||||
|
|
||||||
verifyThatTargetsHaveAssignmentActionType(ActionType.FORCED, targetsA);
|
|
||||||
verifyThatTargetsHaveAssignmentActionType(ActionType.SOFT, targetsB);
|
|
||||||
verifyThatTargetsHaveAssignmentActionType(ActionType.DOWNLOAD_ONLY, targetsC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Step
|
private static String getRandomString() {
|
||||||
private List<Target> createTargetsAndAutoAssignDistSet(final String prefix, final int targetCount,
|
return UUID.randomUUID().toString();
|
||||||
final DistributionSet distributionSet, final ActionType actionType) {
|
|
||||||
|
|
||||||
final List<Target> targets = testdataFactory.createTargets(targetCount, "target" + prefix,
|
|
||||||
prefix.concat(" description"));
|
|
||||||
targetFilterQueryManagement.create(
|
|
||||||
entityFactory.targetFilterQuery().create().name("filter" + prefix).query("id==target" + prefix + "*")
|
|
||||||
.autoAssignDistributionSet(distributionSet).autoAssignActionType(actionType));
|
|
||||||
|
|
||||||
return targets;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Step
|
|
||||||
private void verifyThatTargetsHaveAssignmentActionType(final ActionType actionType, final List<Target> targets) {
|
|
||||||
final List<Action> actions = targets.stream().map(Target::getControllerId).flatMap(
|
|
||||||
controllerId -> deploymentManagement.findActionsByTarget(controllerId, PAGE).getContent().stream())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
assertThat(actions).hasSize(targets.size());
|
|
||||||
assertThat(actions).allMatch(action -> action.getActionType().equals(actionType));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Description("An auto assignment target filter with weight creates actions with weights")
|
|
||||||
void actionsWithWeightAreCreated() throws Exception {
|
|
||||||
final int amountOfTargets = 5;
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
|
||||||
final int weight = 32;
|
|
||||||
enableMultiAssignments();
|
|
||||||
|
|
||||||
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")
|
|
||||||
.autoAssignDistributionSet(ds).autoAssignWeight(weight));
|
|
||||||
testdataFactory.createTargets(amountOfTargets);
|
|
||||||
autoAssignChecker.check();
|
|
||||||
|
|
||||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
|
||||||
assertThat(actions).hasSize(amountOfTargets);
|
|
||||||
assertThat(actions).allMatch(action -> action.getWeight().get() == weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Description("An auto assignment target filter without weight still works after multi assignment is enabled")
|
|
||||||
void filterWithoutWeightWorksInMultiAssignmentMode() throws Exception {
|
|
||||||
final int amountOfTargets = 5;
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
|
||||||
targetFilterQueryManagement.create(
|
|
||||||
entityFactory.targetFilterQuery().create().name("a").query("name==*").autoAssignDistributionSet(ds));
|
|
||||||
enableMultiAssignments();
|
|
||||||
|
|
||||||
testdataFactory.createTargets(amountOfTargets);
|
|
||||||
autoAssignChecker.check();
|
|
||||||
|
|
||||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
|
||||||
assertThat(actions).hasSize(amountOfTargets);
|
|
||||||
assertThat(actions).allMatch(action -> !action.getWeight().isPresent());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Description("Verifies an auto assignment only creates actions for compatible targets")
|
|
||||||
void checkAutoAssignmentWithIncompatibleTargets() {
|
|
||||||
final int TARGET_COUNT = 5;
|
|
||||||
|
|
||||||
final DistributionSet testDs = testdataFactory.createDistributionSet();
|
|
||||||
final DistributionSetType incompatibleDsType1 = testdataFactory
|
|
||||||
.findOrCreateDistributionSetType("incompatibleDsType1", "incompDsType1");
|
|
||||||
final DistributionSetType incompatibleDsType2 = testdataFactory
|
|
||||||
.findOrCreateDistributionSetType("incompatibleDsType2", "incompDsType2");
|
|
||||||
final TargetFilterQuery testFilter = targetFilterQueryManagement.create(entityFactory.targetFilterQuery()
|
|
||||||
.create().name("test-filter").query("name==*").autoAssignDistributionSet(testDs));
|
|
||||||
|
|
||||||
final TargetType incompatibleEmptyType = testdataFactory.createTargetType("incompatibleEmptyType",
|
|
||||||
Collections.emptyList());
|
|
||||||
final TargetType incompatibleSingleType = testdataFactory.createTargetType("incompatibleSingleType",
|
|
||||||
Collections.singletonList(incompatibleDsType1));
|
|
||||||
final TargetType incompatibleMultiType = testdataFactory.createTargetType("incompatibleMultiType",
|
|
||||||
Arrays.asList(incompatibleDsType1, incompatibleDsType2));
|
|
||||||
final TargetType compatibleSingleType = testdataFactory.createTargetType("compatibleSingleType",
|
|
||||||
Collections.singletonList(testDs.getType()));
|
|
||||||
final TargetType compatibleMultiType = testdataFactory.createTargetType("compatibleMultiType",
|
|
||||||
Arrays.asList(testDs.getType(), incompatibleDsType1));
|
|
||||||
|
|
||||||
testdataFactory.createTargetsWithType(TARGET_COUNT, "incompatibleEmpty", incompatibleEmptyType);
|
|
||||||
testdataFactory.createTargetsWithType(TARGET_COUNT, "incompatibleSingle", incompatibleSingleType);
|
|
||||||
testdataFactory.createTargetsWithType(TARGET_COUNT, "incompatibleMulti", incompatibleMultiType);
|
|
||||||
|
|
||||||
final List<Target> compatibleTargetsSingleType = testdataFactory.createTargetsWithType(TARGET_COUNT,
|
|
||||||
"compatibleSingle", compatibleSingleType);
|
|
||||||
final List<Target> compatibleTargetsMultiType = testdataFactory.createTargetsWithType(TARGET_COUNT,
|
|
||||||
"compatibleMulti", compatibleMultiType);
|
|
||||||
final List<Target> compatibleTargetsWithoutType = testdataFactory.createTargets(TARGET_COUNT,
|
|
||||||
"compatibleSingleWithoutType");
|
|
||||||
|
|
||||||
final List<Long> compatibleTargets = Stream
|
|
||||||
.of(compatibleTargetsSingleType, compatibleTargetsMultiType, compatibleTargetsWithoutType)
|
|
||||||
.flatMap(Collection::stream).map(Target::getId).collect(Collectors.toList());
|
|
||||||
final long compatibleCount = targetManagement.countByRsqlAndNonDSAndCompatible(testDs.getId(),
|
|
||||||
testFilter.getQuery());
|
|
||||||
assertThat(compatibleCount).isEqualTo(compatibleTargets.size());
|
|
||||||
|
|
||||||
autoAssignChecker.check();
|
|
||||||
|
|
||||||
final List<Action> actions = deploymentManagement.findActionsAll(Pageable.unpaged()).getContent();
|
|
||||||
assertThat(actions).hasSize(compatibleTargets.size());
|
|
||||||
final List<Long> actionTargets = actions.stream().map(a -> a.getTarget().getId()).collect(Collectors.toList());
|
|
||||||
assertThat(actionTargets).containsExactlyInAnyOrderElementsOf(compatibleTargets);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user