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 { public interface TenantMetaData extends BaseEntity {
/**
* @return default {@link DistributionSetType}.
*/
DistributionSetType getDefaultDsType(); DistributionSetType getDefaultDsType();
/**
* @return tenant name
*/
String getTenant(); String getTenant();
} }

View File

@@ -553,7 +553,9 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Override @Override
public void deleteExistingTarget(@NotEmpty final String controllerId) { 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 @Override

View File

@@ -421,7 +421,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Override @Override
public Optional<DistributionSet> getWithDetails(final long id) { 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 @Override

View File

@@ -128,12 +128,9 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
* @param properties properties to get the underlying database * @param properties properties to get the underlying database
*/ */
public JpaSystemManagement(final JpaProperties properties) { public JpaSystemManagement(final JpaProperties properties) {
final String isDeleted = isPostgreSql(properties) ? "false" : "0"; 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 = " 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;
+ 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;
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 @Override

View File

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

View File

@@ -58,6 +58,12 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
@Column(name = "id") @Column(name = "id")
private Long 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) @Column(name = "created_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
private String createdBy; private String createdBy;
@Column(name = "created_at", updatable = false, nullable = false) @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) @Column(name = "last_modified_at", nullable = false)
private long lastModifiedAt; private long lastModifiedAt;
@Version
@Column(name = "optlock_revision")
private int optLockRevision;
@CreatedBy @CreatedBy
public void setCreatedBy(final String createdBy) { public void setCreatedBy(final String createdBy) {
if (isController()) { if (isController()) {
@@ -170,14 +172,16 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
return false; return false;
} }
final AbstractJpaBaseEntity other = (AbstractJpaBaseEntity) obj; final AbstractJpaBaseEntity other = (AbstractJpaBaseEntity) obj;
final Long id = getId();
final Long otherId = other.getId();
if (id == null) { if (id == null) {
if (other.id != null) { if (otherId != null) {
return false; return false;
} }
} else if (!id.equals(other.id)) { } else if (!id.equals(otherId)) {
return false; return false;
} }
return optLockRevision == other.optLockRevision; return getOptLockRevision() == other.getOptLockRevision();
} }
@Override @Override

View File

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

View File

@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.model;
import java.io.Serial; import java.io.Serial;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -36,11 +37,13 @@ import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.NamedEntityGraphs; import jakarta.persistence.NamedEntityGraphs;
import jakarta.persistence.NamedSubgraph; import jakarta.persistence.NamedSubgraph;
import jakarta.persistence.OneToMany; import jakarta.persistence.OneToMany;
import jakarta.persistence.PostUpdate;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Setter;
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper; import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
@@ -96,42 +99,65 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Column(name = "active") @Column(name = "active")
private boolean active; private boolean active;
@Column(name = "action_type", nullable = false) @Column(name = "action_type", nullable = false)
@Convert(converter = ActionTypeConverter.class) @Convert(converter = ActionTypeConverter.class)
@NotNull @NotNull
private ActionType actionType; private ActionType actionType;
@Column(name = "forced_time") @Column(name = "forced_time")
private long forcedTime; private long forcedTime;
@Setter
@Column(name = "weight") @Column(name = "weight")
@Min(Action.WEIGHT_MIN) @Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX) @Max(Action.WEIGHT_MAX)
private Integer weight; private Integer weight;
@Column(name = "status", nullable = false) @Column(name = "status", nullable = false)
@Convert(converter = StatusConverter.class) @Convert(converter = StatusConverter.class)
@NotNull @NotNull
private Status status; private Status status;
@OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE }) @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) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn( @JoinColumn(
name = "rolloutgroup", updatable = false, name = "rolloutgroup", updatable = false,
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup")) foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup"))
private JpaRolloutGroup rolloutGroup; private JpaRolloutGroup rolloutGroup;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn( @JoinColumn(
name = "rollout", updatable = false, name = "rollout", updatable = false,
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout")) foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
private JpaRollout 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) @Column(name = "maintenance_cron_schedule", updatable = false, length = Action.MAINTENANCE_WINDOW_SCHEDULE_LENGTH)
private String maintenanceWindowSchedule; 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) @Column(name = "maintenance_duration", updatable = false, length = Action.MAINTENANCE_WINDOW_DURATION_LENGTH)
private String maintenanceWindowDuration; 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) @Column(name = "maintenance_time_zone", updatable = false, length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH)
private String maintenanceWindowTimeZone; private String maintenanceWindowTimeZone;
@Column(name = "external_ref", length = Action.EXTERNAL_REF_MAX_LENGTH) @Column(name = "external_ref", length = Action.EXTERNAL_REF_MAX_LENGTH)
private String externalRef; private String externalRef;
@Setter
@Column(name = "initiated_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH) @Column(name = "initiated_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
private String initiatedBy; private String initiatedBy;
@Setter
@Column(name = "last_action_status_code", nullable = true, updatable = true) @Column(name = "last_action_status_code", nullable = true, updatable = true)
private Integer lastActionStatusCode; private Integer lastActionStatusCode;
@@ -194,10 +220,6 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return Optional.ofNullable(weight); return Optional.ofNullable(weight);
} }
public void setWeight(final Integer weight) {
this.weight = weight;
}
@Override @Override
public RolloutGroup getRolloutGroup() { public RolloutGroup getRolloutGroup() {
return rolloutGroup; return rolloutGroup;
@@ -221,47 +243,16 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return maintenanceWindowSchedule; 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 @Override
public String getMaintenanceWindowDuration() { public String getMaintenanceWindowDuration() {
return maintenanceWindowDuration; 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 @Override
public String getMaintenanceWindowTimeZone() { public String getMaintenanceWindowTimeZone() {
return maintenanceWindowTimeZone; 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 @Override
public String getExternalRef() { public String getExternalRef() {
return externalRef; return externalRef;
@@ -277,20 +268,15 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return initiatedBy; return initiatedBy;
} }
public void setInitiatedBy(final String initiatedBy) {
this.initiatedBy = initiatedBy;
}
@Override @Override
public Optional<Integer> getLastActionStatusCode() { public Optional<Integer> getLastActionStatusCode() {
return Optional.ofNullable(lastActionStatusCode); return Optional.ofNullable(lastActionStatusCode);
} }
@Override @Override
public Optional<ZonedDateTime> getMaintenanceWindowStartTime() { public Optional<ZonedDateTime> getMaintenanceWindowStartTime() {
return MaintenanceScheduleHelper.getNextMaintenanceWindow(maintenanceWindowSchedule, maintenanceWindowDuration, return MaintenanceScheduleHelper.getNextMaintenanceWindow(
maintenanceWindowTimeZone); maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
} }
@Override @Override
@@ -330,24 +316,15 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return status == Status.WAIT_FOR_CONFIRMATION; return status == Status.WAIT_FOR_CONFIRMATION;
} }
public void setLastActionStatusCode(final Integer lastActionStatusCode) {
this.lastActionStatusCode = lastActionStatusCode;
}
public List<ActionStatus> getActionStatus() { public List<ActionStatus> getActionStatus() {
if (actionStatus == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(actionStatus); return Collections.unmodifiableList(actionStatus);
} }
@Override @Override
public String toString() { public String toString() {
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id=" return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id=" + getId() +
+ getId() + ", actionType=" + getActionType() + ", weight=" + getWeight() + ", isActive=" + isActive() ", actionType=" + getActionType() + ", weight=" + getWeight() + ", isActive=" + isActive() +
+ ", createdAt=" + getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + ", status=" ", createdAt=" + getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + ", status=" + getStatus().name() + "]";
+ getStatus().name() + "]";
} }
@Override @Override

View File

@@ -132,7 +132,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
@Setter @Setter
@Getter @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")) @JoinColumn(name = "installed_distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds"))
private JpaDistributionSet installedDistributionSet; private JpaDistributionSet installedDistributionSet;

View File

@@ -10,20 +10,18 @@
package org.eclipse.hawkbit.repository.jpa.repository; package org.eclipse.hawkbit.repository.jpa.repository;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManager; 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.acm.AccessController;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; 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.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository; 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>, extends PagingAndSortingRepository<T, Long>, CrudRepository<T, Long>, JpaSpecificationExecutor<T>,
JpaSpecificationEntityGraphExecutor<T>, NoCountSliceRepository<T>, ACMRepository<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 * 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 * 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() { default Optional<AccessController<T>> getAccessController() {
return Optional.empty(); 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) { public static Specification<JpaTarget> hasNotDistributionSetInActions(final Long distributionSetId) {
return (targetRoot, query, cb) -> { return (targetRoot, query, cb) -> {
final ListJoin<JpaTarget, JpaAction> actionsJoin = targetRoot.join(JpaTarget_.actions, JoinType.LEFT); final ListJoin<JpaTarget, JpaAction> actionsJoin = targetRoot.join(JpaTarget_.actions, JoinType.LEFT);
actionsJoin.on(cb.equal(actionsJoin.get(JpaAction_.distributionSet).get(JpaDistributionSet_.id), actionsJoin.on(cb.equal(actionsJoin.get(JpaAction_.distributionSet).get(JpaDistributionSet_.id), distributionSetId));
distributionSetId));
return cb.isNull(actionsJoin.get(JpaAction_.id)); return cb.isNull(actionsJoin.get(JpaAction_.id));
}; };
} }
@@ -308,10 +306,8 @@ public final class TargetSpecifications {
*/ */
public static Specification<JpaTarget> isCompatibleWithDistributionSetType(final Long distributionSetTypeId) { public static Specification<JpaTarget> isCompatibleWithDistributionSetType(final Long distributionSetTypeId) {
return (targetRoot, query, cb) -> { return (targetRoot, query, cb) -> {
// Since the targetRoot is changed by joining we need to get the // Since the targetRoot is changed by joining we need to get the isNull predicate first
// isNull predicate first
final Predicate targetTypeIsNull = getTargetTypeIsNullPredicate(targetRoot); final Predicate targetTypeIsNull = getTargetTypeIsNullPredicate(targetRoot);
return cb.or(targetTypeIsNull, cb.equal(getDsTypeIdPath(targetRoot), distributionSetTypeId)); 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) { public static Specification<JpaTarget> notCompatibleWithDistributionSetType(final Long distributionSetTypeId) {
return (targetRoot, query, cb) -> { return (targetRoot, query, cb) -> {
// Since the targetRoot is changed by joining we need to get the // Since the targetRoot is changed by joining we need to get the isNotNull predicate first
// isNotNull predicate first
final Predicate targetTypeNotNull = targetRoot.get(JpaTarget_.targetType).isNotNull(); final Predicate targetTypeNotNull = targetRoot.get(JpaTarget_.targetType).isNotNull();
final Subquery<Long> compatibilitySubQuery = query.subquery(Long.class); final Subquery<Long> compatibilitySubQuery = query.subquery(Long.class);
final Root<JpaTarget> subQueryTargetRoot = compatibilitySubQuery.from(JpaTarget.class); final Root<JpaTarget> subQueryTargetRoot = compatibilitySubQuery.from(JpaTarget.class);
compatibilitySubQuery.select(subQueryTargetRoot.get(JpaTarget_.id)) 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))); cb.equal(getDsTypeIdPath(subQueryTargetRoot), distributionSetTypeId)));
return cb.and(targetTypeNotNull, cb.not(cb.exists(compatibilitySubQuery))); 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) { private static Path<Long> getDsTypeIdPath(final Root<JpaTarget> root) {
final Join<JpaTarget, JpaTargetType> targetTypeJoin = root.join(JpaTarget_.targetType, JoinType.LEFT); final Join<JpaTarget, JpaTargetType> targetTypeJoin = root.join(JpaTarget_.targetType, JoinType.LEFT);
targetTypeJoin.fetch(JpaTargetType_.distributionSetTypes); return targetTypeJoin.join(JpaTargetType_.distributionSetTypes, JoinType.LEFT).get(JpaDistributionSetType_.id);
final SetJoin<JpaTargetType, JpaDistributionSetType> dsTypeTargetTypeJoin = targetTypeJoin
.join(JpaTargetType_.distributionSetTypes, JoinType.LEFT);
return dsTypeTargetTypeJoin.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.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_; 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.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
@@ -181,12 +180,12 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = createTargetAndAssignDs(); final Long actionId = createTargetAndAssignDs();
// Fails as one entry is already in there from the assignment // 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), () -> { .runAs(SecurityContextSwitch.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
writeStatus(actionId, allowStatusEntries); writeStatus(actionId, allowStatusEntries);
return null; return null;
})).withMessageContaining("" + allowStatusEntries); })).withMessageContaining("" + allowStatusEntries);
} }
@Test @Test

View File

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

View File

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

View File

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

View File

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