Small JPA improvements & test code style (#2122)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-12-06 13:03:48 +02:00
committed by GitHub
parent efc6d051f7
commit 2a476d1268
17 changed files with 243 additions and 324 deletions

View File

@@ -14,14 +14,7 @@ package org.eclipse.hawkbit.repository.model;
*/
public interface TenantMetaData extends BaseEntity {
/**
* @return default {@link DistributionSetType}.
*/
DistributionSetType getDefaultDsType();
/**
* @return tenant name
*/
String getTenant();
}

View File

@@ -553,7 +553,9 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Override
public void deleteExistingTarget(@NotEmpty final String controllerId) {
targetRepository.deleteById(targetRepository.getByControllerId(controllerId).getId());
final JpaTarget target = targetRepository.getByControllerId(controllerId);
targetRepository.deleteById(target.getId());
entityManager.flush();
}
@Override

View File

@@ -421,7 +421,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Override
public Optional<DistributionSet> getWithDetails(final long id) {
return distributionSetRepository.findById(id).map(DistributionSet.class::cast);
return distributionSetRepository
.findOne(distributionSetRepository.byIdSpec(id), JpaDistributionSet_.GRAPH_DISTRIBUTION_SET_DETAIL)
.map(DistributionSet.class::cast);
}
@Override

View File

@@ -128,12 +128,9 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
* @param properties properties to get the underlying database
*/
public JpaSystemManagement(final JpaProperties properties) {
final String isDeleted = isPostgreSql(properties) ? "false" : "0";
countArtifactQuery = "SELECT COUNT(a.id) FROM sp_artifact a INNER JOIN sp_base_software_module sm ON a.software_module = sm.id WHERE sm.deleted = "
+ isDeleted;
countSoftwareModulesQuery = "select SUM(file_size) from sp_artifact a INNER JOIN sp_base_software_module sm ON a.software_module = sm.id WHERE sm.deleted = "
+ isDeleted;
countArtifactQuery = "SELECT COUNT(a.id) FROM sp_artifact a INNER JOIN sp_base_software_module sm ON a.software_module = sm.id WHERE sm.deleted = " + isDeleted;
countSoftwareModulesQuery = "select SUM(file_size) from sp_artifact a INNER JOIN sp_base_software_module sm ON a.software_module = sm.id WHERE sm.deleted = " + isDeleted;
}
@Override

View File

@@ -198,8 +198,8 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public long countByRsqlAndCompatible(final String targetFilterQuery, final Long distributionSetIdTypeId) {
final List<Specification<JpaTarget>> specList = List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery,
TargetFields.class, virtualPropertyReplacer, database),
final List<Specification<JpaTarget>> specList = List.of(RSQLUtility.buildRsqlSpecification(
targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
return JpaManagementHelper.countBySpec(targetRepository, specList);
@@ -207,8 +207,8 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public long countByRsqlAndCompatibleAndUpdatable(String targetFilterQuery, Long distributionSetIdTypeId) {
final List<Specification<JpaTarget>> specList = List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery,
TargetFields.class, virtualPropertyReplacer, database),
final List<Specification<JpaTarget>> specList = List.of(RSQLUtility.buildRsqlSpecification(
targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
return targetRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList));
}

View File

@@ -58,6 +58,12 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
@Column(name = "id")
private Long id;
@Version
@Column(name = "optlock_revision")
private int optLockRevision;
// Audit fields. use property access to ensure that setters will be called and checked for modification
// (touch implementation depends on setLastModifiedAt(0).
@Column(name = "created_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
private String createdBy;
@Column(name = "created_at", updatable = false, nullable = false)
@@ -67,10 +73,6 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
@Column(name = "last_modified_at", nullable = false)
private long lastModifiedAt;
@Version
@Column(name = "optlock_revision")
private int optLockRevision;
@CreatedBy
public void setCreatedBy(final String createdBy) {
if (isController()) {
@@ -170,14 +172,16 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
return false;
}
final AbstractJpaBaseEntity other = (AbstractJpaBaseEntity) obj;
final Long id = getId();
final Long otherId = other.getId();
if (id == null) {
if (other.id != null) {
if (otherId != null) {
return false;
}
} else if (!id.equals(other.id)) {
} else if (!id.equals(otherId)) {
return false;
}
return optLockRevision == other.optLockRevision;
return getOptLockRevision() == other.getOptLockRevision();
}
@Override

View File

@@ -10,6 +10,7 @@
package org.eclipse.hawkbit.repository.jpa.model;
import java.io.Serial;
import java.util.Objects;
import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
@@ -76,11 +77,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
return false;
}
final AbstractJpaTenantAwareBaseEntity other = (AbstractJpaTenantAwareBaseEntity) obj;
if (tenant == null) {
return other.tenant == null;
} else {
return tenant.equals(other.tenant);
}
return Objects.equals(getTenant(), other.getTenant());
}
@Override

View File

@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.model;
import java.io.Serial;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -36,11 +37,13 @@ import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.NamedEntityGraphs;
import jakarta.persistence.NamedSubgraph;
import jakarta.persistence.OneToMany;
import jakarta.persistence.PostUpdate;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Setter;
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
@@ -96,42 +99,65 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Column(name = "active")
private boolean active;
@Column(name = "action_type", nullable = false)
@Convert(converter = ActionTypeConverter.class)
@NotNull
private ActionType actionType;
@Column(name = "forced_time")
private long forcedTime;
@Setter
@Column(name = "weight")
@Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX)
private Integer weight;
@Column(name = "status", nullable = false)
@Convert(converter = StatusConverter.class)
@NotNull
private Status status;
@OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE })
private List<JpaActionStatus> actionStatus;
private List<JpaActionStatus> actionStatus = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "rolloutgroup", updatable = false,
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup"))
private JpaRolloutGroup rolloutGroup;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "rollout", updatable = false,
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
private JpaRollout rollout;
// a cron expression to be used for scheduling.
@Setter
@Column(name = "maintenance_cron_schedule", updatable = false, length = Action.MAINTENANCE_WINDOW_SCHEDULE_LENGTH)
private String maintenanceWindowSchedule;
// the duration of an available maintenance schedule indexes HH:mm:ss format
@Setter
@Column(name = "maintenance_duration", updatable = false, length = Action.MAINTENANCE_WINDOW_DURATION_LENGTH)
private String maintenanceWindowDuration;
// the time zone specified as +/-hh:mm offset from UTC for example +02:00 for CET summer time and +00:00 for UTC. The
// start time of a maintenance window calculated based on the cron expression is relative to this time zone.
@Setter
@Column(name = "maintenance_time_zone", updatable = false, length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH)
private String maintenanceWindowTimeZone;
@Column(name = "external_ref", length = Action.EXTERNAL_REF_MAX_LENGTH)
private String externalRef;
@Setter
@Column(name = "initiated_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
private String initiatedBy;
@Setter
@Column(name = "last_action_status_code", nullable = true, updatable = true)
private Integer lastActionStatusCode;
@@ -194,10 +220,6 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return Optional.ofNullable(weight);
}
public void setWeight(final Integer weight) {
this.weight = weight;
}
@Override
public RolloutGroup getRolloutGroup() {
return rolloutGroup;
@@ -221,47 +243,16 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return maintenanceWindowSchedule;
}
/**
* Sets the maintenance schedule.
*
* @param maintenanceWindowSchedule is a cron expression to be used for scheduling.
*/
public void setMaintenanceWindowSchedule(final String maintenanceWindowSchedule) {
this.maintenanceWindowSchedule = maintenanceWindowSchedule;
}
@Override
public String getMaintenanceWindowDuration() {
return maintenanceWindowDuration;
}
/**
* Sets the maintenance window duration.
*
* @param maintenanceWindowDuration is the duration of an available maintenance schedule in
* HH:mm:ss format.
*/
public void setMaintenanceWindowDuration(final String maintenanceWindowDuration) {
this.maintenanceWindowDuration = maintenanceWindowDuration;
}
@Override
public String getMaintenanceWindowTimeZone() {
return maintenanceWindowTimeZone;
}
/**
* Sets the time zone to be used for maintenance window.
*
* @param maintenanceWindowTimeZone is the time zone specified as +/-hh:mm offset from UTC for
* example +02:00 for CET summer time and +00:00 for UTC. The
* start time of a maintenance window calculated based on the
* cron expression is relative to this time zone.
*/
public void setMaintenanceWindowTimeZone(final String maintenanceWindowTimeZone) {
this.maintenanceWindowTimeZone = maintenanceWindowTimeZone;
}
@Override
public String getExternalRef() {
return externalRef;
@@ -277,20 +268,15 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return initiatedBy;
}
public void setInitiatedBy(final String initiatedBy) {
this.initiatedBy = initiatedBy;
}
@Override
public Optional<Integer> getLastActionStatusCode() {
return Optional.ofNullable(lastActionStatusCode);
}
@Override
public Optional<ZonedDateTime> getMaintenanceWindowStartTime() {
return MaintenanceScheduleHelper.getNextMaintenanceWindow(maintenanceWindowSchedule, maintenanceWindowDuration,
maintenanceWindowTimeZone);
return MaintenanceScheduleHelper.getNextMaintenanceWindow(
maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
}
@Override
@@ -330,24 +316,15 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return status == Status.WAIT_FOR_CONFIRMATION;
}
public void setLastActionStatusCode(final Integer lastActionStatusCode) {
this.lastActionStatusCode = lastActionStatusCode;
}
public List<ActionStatus> getActionStatus() {
if (actionStatus == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(actionStatus);
}
@Override
public String toString() {
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id="
+ getId() + ", actionType=" + getActionType() + ", weight=" + getWeight() + ", isActive=" + isActive()
+ ", createdAt=" + getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + ", status="
+ getStatus().name() + "]";
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id=" + getId() +
", actionType=" + getActionType() + ", weight=" + getWeight() + ", isActive=" + isActive() +
", createdAt=" + getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + ", status=" + getStatus().name() + "]";
}
@Override

View File

@@ -132,7 +132,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
@Setter
@Getter
@ManyToOne(optional = true, fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "installed_distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds"))
private JpaDistributionSet installedDistributionSet;

View File

@@ -10,20 +10,18 @@
package org.eclipse.hawkbit.repository.jpa.repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManager;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
@@ -43,6 +41,10 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
extends PagingAndSortingRepository<T, Long>, CrudRepository<T, Long>, JpaSpecificationExecutor<T>,
JpaSpecificationEntityGraphExecutor<T>, NoCountSliceRepository<T>, ACMRepository<T> {
default T getById(final Long id) {
return findOne(byIdSpec(id)).orElseThrow(() -> new EntityNotFoundException(getManagementClass(), id));
}
/**
* Overrides {@link org.springframework.data.repository.CrudRepository#saveAll(Iterable)} to return a list of created entities instead
* of an instance of {@link Iterable} to be able to work with it directly in further code processing instead of converting the
@@ -133,4 +135,26 @@ public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity
default Optional<AccessController<T>> getAccessController() {
return Optional.empty();
}
@SuppressWarnings("uchecked")
default Class<? extends BaseEntity> getManagementClass() {
final Class<T> domainClass = getDomainClass();
final String domainClassSimpleName = domainClass.getSimpleName();
if (!domainClassSimpleName.toLowerCase().startsWith("jpa")) {
return domainClass;
}
final String managementClassSimpleName = domainClassSimpleName.substring(3);
final Class<?> superClass = domainClass.getSuperclass();
if (superClass != null) {
if (superClass.getSimpleName().equals(managementClassSimpleName) && BaseEntity.class.isAssignableFrom(superClass)) {
return (Class<? extends BaseEntity>)superClass;
}
}
for (final Class<?> interfaceClass : domainClass.getInterfaces()) {
if (interfaceClass.getSimpleName().equals(managementClassSimpleName) && BaseEntity.class.isAssignableFrom(interfaceClass)) {
return (Class<? extends BaseEntity>)interfaceClass;
}
}
return domainClass;
}
}

View File

@@ -290,9 +290,7 @@ public final class TargetSpecifications {
public static Specification<JpaTarget> hasNotDistributionSetInActions(final Long distributionSetId) {
return (targetRoot, query, cb) -> {
final ListJoin<JpaTarget, JpaAction> actionsJoin = targetRoot.join(JpaTarget_.actions, JoinType.LEFT);
actionsJoin.on(cb.equal(actionsJoin.get(JpaAction_.distributionSet).get(JpaDistributionSet_.id),
distributionSetId));
actionsJoin.on(cb.equal(actionsJoin.get(JpaAction_.distributionSet).get(JpaDistributionSet_.id), distributionSetId));
return cb.isNull(actionsJoin.get(JpaAction_.id));
};
}
@@ -308,10 +306,8 @@ public final class TargetSpecifications {
*/
public static Specification<JpaTarget> isCompatibleWithDistributionSetType(final Long distributionSetTypeId) {
return (targetRoot, query, cb) -> {
// Since the targetRoot is changed by joining we need to get the
// isNull predicate first
// Since the targetRoot is changed by joining we need to get the isNull predicate first
final Predicate targetTypeIsNull = getTargetTypeIsNullPredicate(targetRoot);
return cb.or(targetTypeIsNull, cb.equal(getDsTypeIdPath(targetRoot), distributionSetTypeId));
};
}
@@ -328,15 +324,15 @@ public final class TargetSpecifications {
*/
public static Specification<JpaTarget> notCompatibleWithDistributionSetType(final Long distributionSetTypeId) {
return (targetRoot, query, cb) -> {
// Since the targetRoot is changed by joining we need to get the
// isNotNull predicate first
// Since the targetRoot is changed by joining we need to get the isNotNull predicate first
final Predicate targetTypeNotNull = targetRoot.get(JpaTarget_.targetType).isNotNull();
final Subquery<Long> compatibilitySubQuery = query.subquery(Long.class);
final Root<JpaTarget> subQueryTargetRoot = compatibilitySubQuery.from(JpaTarget.class);
compatibilitySubQuery.select(subQueryTargetRoot.get(JpaTarget_.id))
.where(cb.and(cb.equal(targetRoot.get(JpaTarget_.id), subQueryTargetRoot.get(JpaTarget_.id)),
.where(cb.and(
cb.equal(targetRoot.get(JpaTarget_.id), subQueryTargetRoot.get(JpaTarget_.id)),
cb.equal(getDsTypeIdPath(subQueryTargetRoot), distributionSetTypeId)));
return cb.and(targetTypeNotNull, cb.not(cb.exists(compatibilitySubQuery)));
@@ -599,10 +595,6 @@ public final class TargetSpecifications {
private static Path<Long> getDsTypeIdPath(final Root<JpaTarget> root) {
final Join<JpaTarget, JpaTargetType> targetTypeJoin = root.join(JpaTarget_.targetType, JoinType.LEFT);
targetTypeJoin.fetch(JpaTargetType_.distributionSetTypes);
final SetJoin<JpaTargetType, JpaDistributionSetType> dsTypeTargetTypeJoin = targetTypeJoin
.join(JpaTargetType_.distributionSetTypes, JoinType.LEFT);
return dsTypeTargetTypeJoin.get(JpaDistributionSetType_.id);
return targetTypeJoin.join(JpaTargetType_.distributionSetTypes, JoinType.LEFT).get(JpaDistributionSetType_.id);
}
}

View File

@@ -68,7 +68,6 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
@@ -181,12 +180,12 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = createTargetAndAssignDs();
// Fails as one entry is already in there from the assignment
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> SecurityContextSwitch
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> SecurityContextSwitch
.runAs(SecurityContextSwitch.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
writeStatus(actionId, allowStatusEntries);
return null;
})).withMessageContaining("" + allowStatusEntries);
}
@Test

View File

@@ -33,6 +33,7 @@ import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import lombok.Getter;
import org.assertj.core.api.Assertions;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.DeploymentManagement;
@@ -114,7 +115,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThatExceptionOfType(IncompleteDistributionSetException.class)
.as("Incomplete distributionSet should throw an exception")
.isThrownBy(() -> assignDistributionSet(distributionSet, target));
}
@Test
@@ -126,27 +126,12 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThatExceptionOfType(InvalidDistributionSetException.class)
.as("Invalid distributionSet should throw an exception")
.isThrownBy(() -> assignDistributionSet(distributionSet, target));
}
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight) {
return createAssignmentRequests(distributionSets, targets, weight, false);
}
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight, final boolean confirmationRequired) {
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
distributionSets.forEach(ds -> targets.forEach(target -> deploymentRequests
.add(DeploymentManagement.deploymentRequest(target.getControllerId(), ds.getId()).setWeight(weight)
.setConfirmationRequired(confirmationRequired).build())));
return deploymentRequests;
}
@Test
@Description("Verifies that management get access react as specified on calls for non existing entities by means " +
"of Optional not present.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) })
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class) })
void nonExistingEntityAccessReturnsNotPresent() {
assertThat(deploymentManagement.findAction(1234L)).isNotPresent();
assertThat(deploymentManagement.findActionWithDetails(NOT_EXIST_IDL)).isNotPresent();
@@ -190,22 +175,20 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(action.getDistributionSet()).as("DistributionSet in action").isNotNull();
assertThat(action.getTarget()).as("Target in action").isNotNull();
assertThat(deploymentManagement.getAssignedDistributionSet(action.getTarget().getControllerId()).get())
.as("AssignedDistributionSet of target in action").isNotNull();
.as("AssignedDistributionSet of target in action")
.isNotNull();
}
@Test
@Description("Test verifies that actions of a target are found by using id-based search.")
void findActionByTargetId() {
final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0",
new ArrayList<>());
final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0", new ArrayList<>());
final List<Target> testTarget = testdataFactory.createTargets(1);
// one action with one action status is generated
final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget));
// act
final Slice<Action> actions = deploymentManagement.findActionsByTarget(testTarget.get(0).getControllerId(),
PAGE);
final Slice<Action> actions = deploymentManagement.findActionsByTarget(testTarget.get(0).getControllerId(), PAGE);
final Long count = deploymentManagement.countActionsByTarget(testTarget.get(0).getControllerId());
assertThat(count).as("One Action for target").isEqualTo(1L).isEqualTo(actions.getContent().size());
@@ -215,7 +198,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Test verifies that the 'max actions per target' quota is enforced.")
void assertMaxActionsPerTargetQuotaIsEnforced() {
final int maxActions = quotaManagement.getMaxActionsPerTarget();
final Target testTarget = testdataFactory.createTarget();
final DistributionSet ds1 = testdataFactory.createDistributionSet("ds1");
@@ -223,7 +205,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
enableMultiAssignments();
for (int i = 0; i < maxActions; i++) {
deploymentManagement.offlineAssignedDistributionSets(Collections
.singletonList(new SimpleEntry<String, Long>(testTarget.getControllerId(), ds1.getId())));
.singletonList(new SimpleEntry<>(testTarget.getControllerId(), ds1.getId())));
}
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
@@ -241,8 +223,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assignDistributionSet(ds1, targets);
targets.add(testdataFactory.createTarget("assignmentTest2"));
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> assignDistributionSet(ds2, targets));
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> assignDistributionSet(ds2, targets));
}
@Test
@@ -266,8 +247,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Test verifies that messages of an action-status are found by using id-based search.")
void findMessagesByActionStatusId() {
final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0",
new ArrayList<DistributionSetTag>());
final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0", new ArrayList<>());
final List<Target> testTarget = testdataFactory.createTargets(1);
// one action with one action status is generated
final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget));
@@ -277,8 +257,10 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final Page<ActionStatus> actionStates = deploymentManagement.findActionStatusByAction(PAGE, actionId);
// find newly created action-status entry with message
final JpaActionStatus actionStatusWithMessage = actionStates.getContent().stream().map(c -> (JpaActionStatus) c)
.filter(entry -> entry.getMessages() != null && entry.getMessages().size() > 0).findFirst().get();
final JpaActionStatus actionStatusWithMessage = actionStates.getContent().stream()
.map(JpaActionStatus.class::cast)
.filter(entry -> entry.getMessages() != null && !entry.getMessages().isEmpty())
.findFirst().get();
final String expectedMsg = actionStatusWithMessage.getMessages().get(0);
// act
@@ -302,7 +284,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThatExceptionOfType(EntityNotFoundException.class)
.isThrownBy(() -> distributionSetManagement.assignTag(assignDS, tag.getId()))
.withMessageContaining("DistributionSet").withMessageContaining(String.valueOf(100L));
.withMessageContaining("DistributionSet")
.withMessageContaining(String.valueOf(100L));
}
@Test
@@ -320,13 +303,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) })
// implicit lock })
void multiAssigmentHistoryOverMultiplePagesResultsInTwoActiveAction() {
final DistributionSet cancelDs = testdataFactory.createDistributionSet("Canceled DS", "1.0",
Collections.emptyList());
final DistributionSet cancelDs2 = testdataFactory.createDistributionSet("Canceled DS", "1.2",
Collections.emptyList());
final DistributionSet cancelDs = testdataFactory.createDistributionSet("Canceled DS", "1.0", Collections.emptyList());
final DistributionSet cancelDs2 = testdataFactory.createDistributionSet("Canceled DS", "1.2", Collections.emptyList());
final List<Target> targets = testdataFactory.createTargets(quotaManagement.getMaxTargetsPerAutoAssignment());
assertThat(deploymentManagement.countActionsAll()).isZero();
@@ -334,14 +312,13 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assignDistributionSet(cancelDs, targets).getAssignedEntity();
assertThat(deploymentManagement.countActionsAll()).isEqualTo(quotaManagement.getMaxTargetsPerAutoAssignment());
assignDistributionSet(cancelDs2, targets).getAssignedEntity();
assertThat(deploymentManagement.countActionsAll())
.isEqualTo(2L * quotaManagement.getMaxTargetsPerAutoAssignment());
assertThat(deploymentManagement.countActionsAll()).isEqualTo(2L * quotaManagement.getMaxTargetsPerAutoAssignment());
}
@Test
@Description("Cancels multiple active actions on a target. Expected behaviour is that with two active "
+ "actions after canceling the second active action the first one is still running as it is not touched by the cancelation. After canceling the first one "
+ "also the target goes back to IN_SYNC as no open action is left.")
@Description("Cancels multiple active actions on a target. Expected behaviour is that with two active " +
"actions after canceling the second active action the first one is still running as it is not touched by the cancelation. " +
"After canceling the first one also the target goes back to IN_SYNC as no open action is left.")
void manualCancelWithMultipleAssignmentsCancelLastOneFirst() {
final Action action = prepareFinishedUpdate("4712", "installed", true);
final Target target = action.getTarget();
@@ -350,7 +327,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final DistributionSet dsInstalled = action.getDistributionSet();
// check initial status
assertThat(targetManagement.getByControllerID("4712").get().getUpdateStatus()).as("target has update status")
assertThat(targetManagement.getByControllerID("4712").get().getUpdateStatus())
.as("target has update status")
.isEqualTo(TargetUpdateStatus.IN_SYNC);
// assign the two sets in a row
@@ -364,11 +342,11 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
deploymentManagement.cancelAction(secondAction.getId());
secondAction = (JpaAction) deploymentManagement.findActionWithDetails(secondAction.getId()).get();
// confirm cancellation
controllerManagement.addCancelActionStatus(
entityFactory.actionStatus().create(secondAction.getId()).status(Status.CANCELED));
controllerManagement.addCancelActionStatus(entityFactory.actionStatus().create(secondAction.getId()).status(Status.CANCELED));
assertThat(actionStatusRepository.findAll()).as("wrong size of actions status").hasSize(7);
assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong ds").contains(dsFirst);
assertThat(targetManagement.getByControllerID("4712").get().getUpdateStatus()).as("wrong update status")
assertThat(targetManagement.getByControllerID("4712").get().getUpdateStatus())
.as("wrong update status")
.isEqualTo(TargetUpdateStatus.PENDING);
// we cancel first -> back to installed
@@ -434,7 +412,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Force Quit an Assignment. Expected behaviour is that the action is canceled and is marked as deleted. The assigned Software module")
void forceQuitSetActionToInactive() throws InterruptedException {
void forceQuitSetActionToInactive() {
final Action action = prepareFinishedUpdate("4712", "installed", true);
final Target target = action.getTarget();
final DistributionSet dsInstalled = action.getDistributionSet();
@@ -506,7 +484,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final List<String> controllerIds = testdataFactory.createTargets(10).stream().map(Target::getControllerId)
.collect(Collectors.toList());
final List<Target> onlineAssignedTargets = testdataFactory.createTargets(10, "2");
controllerIds.addAll(onlineAssignedTargets.stream().map(Target::getControllerId).collect(Collectors.toList()));
controllerIds.addAll(onlineAssignedTargets.stream().map(Target::getControllerId).toList());
final DistributionSet ds = testdataFactory.createDistributionSet();
assignDistributionSet(testdataFactory.createDistributionSet("2"), onlineAssignedTargets);
@@ -514,7 +492,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final long current = System.currentTimeMillis();
final List<Entry<String, Long>> offlineAssignments = controllerIds.stream()
.map(targetId -> new SimpleEntry<String, Long>(targetId, ds.getId())).collect(Collectors.toList());
.map(targetId -> new SimpleEntry<>(targetId, ds.getId())).collect(Collectors.toList());
final List<DistributionSetAssignmentResult> assignmentResults = deploymentManagement
.offlineAssignedDistributionSets(offlineAssignments);
assertThat(assignmentResults).hasSize(1);
@@ -548,15 +526,12 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 12), // implicit lock
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void multiOfflineAssignment() {
final List<String> targetIds = testdataFactory.createTargets(1).stream().map(Target::getControllerId)
.collect(Collectors.toList());
final List<Long> dsIds = testdataFactory.createDistributionSets(4).stream().map(DistributionSet::getId)
.collect(Collectors.toList());
final List<String> targetIds = testdataFactory.createTargets(1).stream().map(Target::getControllerId).toList();
final List<Long> dsIds = testdataFactory.createDistributionSets(4).stream().map(DistributionSet::getId).toList();
enableMultiAssignments();
final List<Entry<String, Long>> offlineAssignments = new ArrayList<>();
targetIds.forEach(targetId -> dsIds
.forEach(dsId -> offlineAssignments.add(new SimpleEntry<String, Long>(targetId, dsId))));
targetIds.forEach(targetId -> dsIds.forEach(dsId -> offlineAssignments.add(new SimpleEntry<>(targetId, dsId))));
final List<DistributionSetAssignmentResult> assignmentResults = deploymentManagement
.offlineAssignedDistributionSets(offlineAssignments);
@@ -565,7 +540,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final List<Long> assignedDsIds = deploymentManagement.findActionsByTarget(controllerId, PAGE).stream()
.map(a -> {
// don't use peek since it is by documentation mainly for debugging and could be skipped in some cases
assertThat(a.getInitiatedBy()).as("Actions should be initiated by current user")
assertThat(a.getInitiatedBy())
.as("Actions should be initiated by current user")
.isEqualTo(tenantAware.getCurrentUsername());
return a;
})
@@ -628,8 +604,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6), // implicit lock
@Expect(type = MultiActionAssignEvent.class, count = 2),
@Expect(type = MultiActionCancelEvent.class, count = 0),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void previousAssignmentsAreNotCanceledInMultiAssignMode() {
enableMultiAssignments();
@@ -661,7 +635,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = DistributionSetUpdatedEvent.class, count = 4), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 12), // implicit lock
@Expect(type = MultiActionAssignEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void multiAssignmentInOneRequest() {
final List<Target> targets = testdataFactory.createTargets(1);
@@ -701,7 +674,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = MultiActionAssignEvent.class, count = 1),
@Expect(type = MultiActionCancelEvent.class, count = 4),
@Expect(type = ActionUpdatedEvent.class, count = 4),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void cancelMultiAssignmentActions() {
final List<Target> targets = testdataFactory.createTargets(1);
@@ -716,14 +688,13 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(getResultingActionCount(results)).isEqualTo(deploymentRequests.size());
final List<Long> dsIds = distributionSets.stream().map(DistributionSet::getId).collect(Collectors.toList());
targets.forEach(target -> {
targets.forEach(target ->
deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).forEach(action -> {
assertThat(action.getDistributionSet().getId()).isIn(dsIds);
assertThat(action.getInitiatedBy()).as("Should be Initiated by current user")
.isEqualTo(tenantAware.getCurrentUsername());
deploymentManagement.cancelAction(action.getId());
});
});
}));
}
@Test
@@ -785,7 +756,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(getResultingActionCount(results)).isEqualTo(controllerIds.size());
controllerIds.forEach(controllerId -> {
controllerIds.forEach(controllerId ->
deploymentManagement.findActionsByTarget(controllerId, PAGE).forEach(action -> {
assertThat(action.getDistributionSet().getId()).isIn(distributionSet.getId());
assertThat(action.getInitiatedBy()).as("Should be Initiated by current user")
@@ -795,8 +766,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
} else {
assertThat(action.getStatus()).isEqualTo(RUNNING);
}
});
});
}));
}
@ParameterizedTest
@@ -831,9 +801,12 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
// auto-confirmation will perform the confirmation
assertThat(actionStatus.getMessages())
.contains("Assignment initiated by user 'bumlux'")
.contains("Assignment automatically confirmed by initiator 'not_bumlux'. \n"
+ "\n" + "Auto confirmation activated by system user: 'bumlux' \n"
+ "\n" + "Remark: my personal remark");
.contains("""
Assignment automatically confirmed by initiator 'not_bumlux'.\s
Auto confirmation activated by system user: 'bumlux'\s
Remark: my personal remark""");
} else {
// assignment never required confirmation, auto-confirmation will not be
// applied.
@@ -896,19 +869,17 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assignDistributionSetToTargets(distributionSet, targets2, false).stream()) //
.collect(Collectors.toList());
final List<String> controllerIds = Stream.concat(targets1.stream(), targets2.stream())
.collect(Collectors.toList());
final List<String> controllerIds = Stream.concat(targets1.stream(), targets2.stream()).toList();
assertThat(getResultingActionCount(results)).isEqualTo(controllerIds.size());
controllerIds.forEach(controllerId -> {
controllerIds.forEach(controllerId ->
deploymentManagement.findActionsByTarget(controllerId, PAGE).forEach(action -> {
assertThat(action.getDistributionSet().getId()).isIn(distributionSet.getId());
assertThat(action.getInitiatedBy()).as("Should be Initiated by current user")
.isEqualTo(tenantAware.getCurrentUsername());
assertThat(action.getStatus()).isEqualTo(RUNNING);
});
});
}));
}
@Test
@@ -947,7 +918,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 21), // max actions per target are 20 for test
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3 * 21),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void maxActionsPerTargetIsCheckedBeforeAssignmentExecution() {
final int maxActions = quotaManagement.getMaxActionsPerTarget();
@@ -1165,9 +1135,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(page.getTotalElements()).as("wrong size of actions")
.isEqualTo(noOfDeployedTargets * noOfDistributionSets);
// only records retrieved from the DB can be evaluated to be sure that
// all fields are
// populated;
// only records retrieved from the DB can be evaluated to be sure that all fields are populated;
final List<JpaTarget> allFoundTargets = targetRepository.findAll();
final List<JpaTarget> deployedTargetsFromDB = targetRepository.findAllById(deployedTargetIDs);
@@ -1210,9 +1178,9 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final JpaDistributionSet dsC = (JpaDistributionSet) deployResWithDsC.getDistributionSets().get(0);
// retrieving the UpdateActions created by the assignments
findActionsByDistributionSet(pageRequest, dsA.getId()).getContent().get(0);
findActionsByDistributionSet(pageRequest, dsB.getId()).getContent().get(0);
findActionsByDistributionSet(pageRequest, dsC.getId()).getContent().get(0);
assertThat(findActionsByDistributionSet(pageRequest, dsA.getId()).getContent()).isNotEmpty();
assertThat(findActionsByDistributionSet(pageRequest, dsB.getId()).getContent()).isNotEmpty();
assertThat(findActionsByDistributionSet(pageRequest, dsC.getId()).getContent()).isNotEmpty();
// verifying the correctness of the assignments
for (final Target t : deployResWithDsA.getDeployedTargets()) {
@@ -1531,8 +1499,9 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(assignmentResult.getAssigned()).as("Total count of assigned targets").isEqualTo(1);
assertThat(assignmentResult.getAlreadyAssigned()).as("Total count of already assigned targets").isEqualTo(1);
assertThat(assignmentResult.getAssignedEntity()).isNotEmpty();
final DistributionSet actionDistributionSet = distributionSetRepository.getById(action.getDistributionSet().getId());
assertThat(assignmentResult.getAssignedEntity()).allMatch(
a -> a.getTarget().equals(target3) && a.getDistributionSet().equals(action.getDistributionSet()));
a -> a.getTarget().equals(target3) && a.getDistributionSet().equals(actionDistributionSet));
assertThat(assignmentResult.getAssignedEntity())
.noneMatch(a -> a.getTarget().getControllerId().equals("target1"));
}
@@ -1642,6 +1611,20 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests));
}
private List<DeploymentRequest> createAssignmentRequests(
final Collection<DistributionSet> distributionSets, final Collection<Target> targets, final int weight) {
return createAssignmentRequests(distributionSets, targets, weight, false);
}
private List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight, final boolean confirmationRequired) {
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
distributionSets.forEach(ds -> targets.forEach(target -> deploymentRequests
.add(DeploymentManagement.deploymentRequest(target.getControllerId(), ds.getId()).setWeight(weight)
.setConfirmationRequired(confirmationRequired).build())));
return deploymentRequests;
}
private JpaAction assignSet(final Target target, final DistributionSet ds) {
assignDistributionSet(ds.getId(), target.getControllerId());
implicitLock(ds);
@@ -1715,10 +1698,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
"first description");
// creating 10 DistributionSets
final Collection<DistributionSet> dsList = testdataFactory.createDistributionSets(distributionSetPrefix,
noOfDistributionSets);
String time = String.valueOf(System.currentTimeMillis());
time = time.substring(time.length() - 5);
final Collection<DistributionSet> dsList = testdataFactory.createDistributionSets(distributionSetPrefix, noOfDistributionSets);
// assigning all DistributionSet to the Target in the list
// deployedTargets
@@ -1728,66 +1708,36 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
implicitLock(ds);
}
return new DeploymentResult(deployedTargets, nakedTargets, dsList, deployedTargetPrefix, undeployedTargetPrefix,
distributionSetPrefix);
return new DeploymentResult(deployedTargets, nakedTargets, dsList);
}
private Slice<Action> findActionsByDistributionSet(final Pageable pageable, final long distributionSetId) {
distributionSetManagement.get(distributionSetId).orElseThrow(() -> new EntityNotFoundException(
DistributionSet.class, distributionSetId));
distributionSetManagement.get(distributionSetId).orElseThrow(() ->
new EntityNotFoundException(DistributionSet.class, distributionSetId));
return actionRepository
.findAll(ActionSpecifications.byDistributionSetId(distributionSetId), pageable)
.map(Action.class::cast);
}
@Getter
private static class DeploymentResult {
final List<Long> deployedTargetIDs = new ArrayList<>();
final List<Long> undeployedTargetIDs = new ArrayList<>();
final List<Long> distributionSetIDs = new ArrayList<>();
private final List<Long> deployedTargetIDs = new ArrayList<>();
private final List<Long> undeployedTargetIDs = new ArrayList<>();
private final List<Long> distributionSetIDs = new ArrayList<>();
private final List<Target> undeployedTargets = new ArrayList<>();
private final List<Target> deployedTargets = new ArrayList<>();
private final List<DistributionSet> distributionSets = new ArrayList<>();
public DeploymentResult(final Iterable<Target> deployedTs, final Iterable<Target> undeployedTs,
final Iterable<DistributionSet> dss, final String deployedTargetPrefix,
final String undeployedTargetPrefix, final String distributionSetPrefix) {
private DeploymentResult(final Iterable<Target> deployedTs, final Iterable<Target> undeployedTs, final Iterable<DistributionSet> dss) {
deployedTargets.addAll(toList(deployedTs));
undeployedTargets.addAll(toList(undeployedTs));
distributionSets.addAll(toList(dss));
deployedTargets.forEach(t -> deployedTargetIDs.add(t.getId()));
undeployedTargets.forEach(t -> undeployedTargetIDs.add(t.getId()));
distributionSets.forEach(ds -> distributionSetIDs.add(ds.getId()));
}
public List<Long> getDistributionSetIDs() {
return distributionSetIDs;
}
public List<Long> getDeployedTargetIDs() {
return deployedTargetIDs;
}
public List<Target> getUndeployedTargets() {
return undeployedTargets;
}
public List<DistributionSet> getDistributionSets() {
return distributionSets;
}
public List<Target> getDeployedTargets() {
return deployedTargets;
}
public List<Long> getUndeployedTargetIDs() {
return undeployedTargetIDs;
}
}
}

View File

@@ -49,8 +49,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
@Test
@Description("Verify invalidation of distribution sets that only removes distribution sets from auto assignments")
void verifyInvalidateDistributionSetStopAutoAssignment() {
final InvalidationTestData invalidationTestData = createInvalidationTestData(
"verifyInvalidateDistributionSetStopAutoAssignment");
final InvalidationTestData invalidationTestData = createInvalidationTestData("verifyInvalidateDistributionSetStopAutoAssignment");
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), CancelationType.NONE,

View File

@@ -85,13 +85,13 @@ import org.springframework.data.domain.Sort.Direction;
@Story("DistributionSet Management")
class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
public static final String TAG1_NAME = "Tag1";
private static final String TAG1_NAME = "Tag1";
@Autowired
RepositoryProperties repositoryProperties;
@Test
@Description("Verifies that management get access react as specified on calls for non existing entities by means "
+ "of Optional not present.")
@Description("Verifies that management get access react as specified on calls for non existing entities by means of Optional not present.")
@ExpectEvents({
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
@@ -104,8 +104,8 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Verifies that management queries react as specfied on calls for non existing entities "
+ " by means of throwing EntityNotFoundException.")
@Description("Verifies that management queries react as specified on calls for non existing entities by means of " +
"throwing EntityNotFoundException.")
@ExpectEvents({
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@@ -116,52 +116,36 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
final SoftwareModule module = testdataFactory.createSoftwareModuleApp();
verifyThrownExceptionBy(
() -> distributionSetManagement.assignSoftwareModules(NOT_EXIST_IDL, singletonList(module.getId())),
"DistributionSet");
() -> distributionSetManagement.assignSoftwareModules(NOT_EXIST_IDL, singletonList(module.getId())), "DistributionSet");
verifyThrownExceptionBy(
() -> distributionSetManagement.assignSoftwareModules(set.getId(), singletonList(NOT_EXIST_IDL)),
"SoftwareModule");
() -> distributionSetManagement.assignSoftwareModules(set.getId(), singletonList(NOT_EXIST_IDL)), "SoftwareModule");
verifyThrownExceptionBy(() -> distributionSetManagement.countByTypeId(NOT_EXIST_IDL), "DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.unassignSoftwareModule(NOT_EXIST_IDL, module.getId()),
"DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.unassignSoftwareModule(set.getId(), NOT_EXIST_IDL),
"SoftwareModule");
verifyThrownExceptionBy(() -> distributionSetManagement.unassignSoftwareModule(NOT_EXIST_IDL, module.getId()), "DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.unassignSoftwareModule(set.getId(), NOT_EXIST_IDL), "SoftwareModule");
verifyThrownExceptionBy(() -> distributionSetManagement.assignTag(singletonList(set.getId()), NOT_EXIST_IDL),
"DistributionSetTag");
verifyThrownExceptionBy(() -> distributionSetManagement.assignTag(singletonList(NOT_EXIST_IDL), dsTag.getId()),
"DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.assignTag(singletonList(set.getId()), NOT_EXIST_IDL), "DistributionSetTag");
verifyThrownExceptionBy(() -> distributionSetManagement.assignTag(singletonList(NOT_EXIST_IDL), dsTag.getId()), "DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.findByTag(PAGE, NOT_EXIST_IDL), "DistributionSetTag");
verifyThrownExceptionBy(() -> distributionSetManagement.findByRsqlAndTag(PAGE, "name==*", NOT_EXIST_IDL),
"DistributionSetTag");
verifyThrownExceptionBy(() -> distributionSetManagement.findByRsqlAndTag(PAGE, "name==*", NOT_EXIST_IDL), "DistributionSetTag");
verifyThrownExceptionBy(
() -> distributionSetManagement.assignTag(singletonList(NOT_EXIST_IDL), dsTag.getId()),
"DistributionSet");
verifyThrownExceptionBy(
() -> distributionSetManagement.assignTag(singletonList(set.getId()), Long.parseLong(NOT_EXIST_ID)),
"DistributionSetTag");
verifyThrownExceptionBy(() -> distributionSetManagement.assignTag(singletonList(NOT_EXIST_IDL), dsTag.getId()), "DistributionSet");
verifyThrownExceptionBy(() ->
distributionSetManagement.assignTag(singletonList(set.getId()), Long.parseLong(NOT_EXIST_ID)), "DistributionSetTag");
verifyThrownExceptionBy(() -> distributionSetManagement.unassignTag(set.getId(), NOT_EXIST_IDL),
"DistributionSetTag");
verifyThrownExceptionBy(() -> distributionSetManagement.unassignTag(set.getId(), NOT_EXIST_IDL), "DistributionSetTag");
verifyThrownExceptionBy(() -> distributionSetManagement.unassignTag(NOT_EXIST_IDL, dsTag.getId()),
"DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.unassignTag(NOT_EXIST_IDL, dsTag.getId()), "DistributionSet");
verifyThrownExceptionBy(
() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("xxx").type(NOT_EXIST_ID)),
"DistributionSetType");
verifyThrownExceptionBy(() -> distributionSetManagement.create(
entityFactory.distributionSet().create().name("xxx").type(NOT_EXIST_ID)), "DistributionSetType");
verifyThrownExceptionBy(() -> distributionSetManagement.createMetaData(NOT_EXIST_IDL,
singletonList(entityFactory.generateDsMetadata("123", "123"))), "DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.createMetaData(
NOT_EXIST_IDL, singletonList(entityFactory.generateDsMetadata("123", "123"))), "DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.delete(singletonList(NOT_EXIST_IDL)),
"DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.delete(singletonList(NOT_EXIST_IDL)), "DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.delete(NOT_EXIST_IDL), "DistributionSet");
verifyThrownExceptionBy(() -> distributionSetManagement.deleteMetaData(NOT_EXIST_IDL, "xxx"),
"DistributionSet");
@@ -249,22 +233,20 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Verifies that multiple DS are of default type if not specified explicitly at creation time.")
void createMultipleDistributionSetsWithImplicitType() {
final List<DistributionSetCreate> creates = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
creates.add(entityFactory.distributionSet().create().name("newtypesoft" + i).version("1" + i));
}
final List<DistributionSet> sets = distributionSetManagement.create(creates);
assertThat(sets).as("Type should be equal to default type of tenant").are(new Condition<DistributionSet>() {
assertThat(distributionSetManagement.create(creates))
.as("Type should be equal to default type of tenant")
.are(new Condition<>() {
@Override
public boolean matches(final DistributionSet value) {
return value.getType().equals(systemManagement.getTenantMetadata().getDefaultDsType());
}
});
}
@Test
@@ -338,13 +320,13 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
assignDS.add(testdataFactory.createDistributionSet("DS" + i, "1.0", Collections.emptyList()).getId());
}
final DistributionSetTag tag = distributionSetTagManagement
.create(entityFactory.tag().create().name(TAG1_NAME));
final DistributionSetTag tag = distributionSetTagManagement.create(entityFactory.tag().create().name(TAG1_NAME));
final List<DistributionSet> assignedDS = distributionSetManagement.assignTag(assignDS, tag.getId());
assertThat(assignedDS.size()).as("assigned ds has wrong size").isEqualTo(4);
assignedDS.stream().map(c -> (JpaDistributionSet) c)
.forEach(ds -> assertThat(ds.getTags().size()).as("ds has wrong tag size").isEqualTo(1));
assignedDS.stream().map(JpaDistributionSet.class::cast).forEach(ds -> assertThat(ds.getTags().size())
.as("ds has wrong tag size")
.isEqualTo(1));
final DistributionSetTag findDistributionSetTag = getOrThrow(distributionSetTagManagement.getByName(TAG1_NAME));
@@ -1046,16 +1028,15 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Get the Rollouts count by status statistics for a specific Distribution Set")
void getActionsCountStatisticsForDistributionSet() {
DistributionSet ds = testdataFactory.createDistributionSet("DS");
DistributionSet ds2 = testdataFactory.createDistributionSet("DS2");
final DistributionSet ds = testdataFactory.createDistributionSet("DS");
final DistributionSet ds2 = testdataFactory.createDistributionSet("DS2");
testdataFactory.createTargets("targets", 4);
Rollout rollout = testdataFactory.createRolloutByVariables("rollout", "description",
1, "name==targets*", ds, "50", "5", false);
final Rollout rollout = testdataFactory.createRolloutByVariables("rollout", "description", 1, "name==targets*", ds, "50", "5", false);
rolloutManagement.start(rollout.getId());
rolloutHandler.handleAll();
List<Statistic> statistics = distributionSetManagement.countActionsByStatusForDistributionSet(ds.getId());
final List<Statistic> statistics = distributionSetManagement.countActionsByStatusForDistributionSet(ds.getId());
assertThat(statistics).hasSize(1);
assertThat(distributionSetManagement.countActionsByStatusForDistributionSet(ds2.getId())).isEmpty();

View File

@@ -296,9 +296,7 @@ public class TestdataFactory {
* @param isRequiredMigrationStep for {@link DistributionSet#isRequiredMigrationStep()}
* @return {@link DistributionSet} entity.
*/
public DistributionSet createDistributionSet(final String prefix, final String version,
final boolean isRequiredMigrationStep) {
public DistributionSet createDistributionSet(final String prefix, final String version, final boolean isRequiredMigrationStep) {
final SoftwareModule appMod = softwareModuleManagement.create(entityFactory.softwareModule().create()
.type(findOrCreateSoftwareModuleType(SM_TYPE_APP, Integer.MAX_VALUE)).name(prefix + SM_TYPE_APP)
.version(version + "." + new SecureRandom().nextInt(100)).description(randomDescriptionLong())

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.security;
import java.util.Optional;
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -58,6 +59,9 @@ public class SpringSecurityAuditorAware implements AuditorAware<String> {
}
protected String getCurrentAuditor(final Authentication authentication) {
if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails && tenantAwareDetails.isController()) {
return "CONTROLLER_PLUG_AND_PLAY";
}
if (authentication.getPrincipal() instanceof UserDetails) {
return ((UserDetails) authentication.getPrincipal()).getUsername();
}