Improve artifact binary cleanup - only after commit (#2134)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -476,9 +476,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateTotalTargetCount(final JpaRolloutGroup rolloutGroup, final long countTargetsOfRolloutGroup) {
|
private void updateTotalTargetCount(final JpaRolloutGroup rolloutGroup, final long countTargetsOfRolloutGroup) {
|
||||||
final JpaRollout jpaRollout = (JpaRollout) rolloutGroup.getRollout();
|
final JpaRollout jpaRollout = rolloutGroup.getRollout();
|
||||||
final long updatedTargetCount = jpaRollout.getTotalTargets()
|
final long updatedTargetCount = jpaRollout.getTotalTargets() - (rolloutGroup.getTotalTargets() - countTargetsOfRolloutGroup);
|
||||||
- (rolloutGroup.getTotalTargets() - countTargetsOfRolloutGroup);
|
|
||||||
jpaRollout.setTotalTargets(updatedTargetCount);
|
jpaRollout.setTotalTargets(updatedTargetCount);
|
||||||
rolloutGroup.setTotalTargets((int) countTargetsOfRolloutGroup);
|
rolloutGroup.setTotalTargets((int) countTargetsOfRolloutGroup);
|
||||||
rolloutRepository.save(jpaRollout);
|
rolloutRepository.save(jpaRollout);
|
||||||
@@ -574,12 +573,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
|
|
||||||
private boolean ensureAllGroupsAreScheduled(final Rollout rollout) {
|
private boolean ensureAllGroupsAreScheduled(final Rollout rollout) {
|
||||||
final JpaRollout jpaRollout = (JpaRollout) rollout;
|
final JpaRollout jpaRollout = (JpaRollout) rollout;
|
||||||
|
final List<JpaRolloutGroup> groupsToBeScheduled = rolloutGroupRepository.findByRolloutAndStatus(rollout, RolloutGroupStatus.READY);
|
||||||
final List<JpaRolloutGroup> groupsToBeScheduled = rolloutGroupRepository.findByRolloutAndStatus(rollout,
|
final long scheduledGroups = groupsToBeScheduled.stream().filter(group -> scheduleRolloutGroup(jpaRollout, group)).count();
|
||||||
RolloutGroupStatus.READY);
|
|
||||||
final long scheduledGroups = groupsToBeScheduled.stream()
|
|
||||||
.filter(group -> scheduleRolloutGroup(jpaRollout, group)).count();
|
|
||||||
|
|
||||||
return scheduledGroups == groupsToBeScheduled.size();
|
return scheduledGroups == groupsToBeScheduled.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,8 +625,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
|||||||
do {
|
do {
|
||||||
// Add up to TRANSACTION_TARGETS of the left targets
|
// Add up to TRANSACTION_TARGETS of the left targets
|
||||||
// In case a TransactionException is thrown this loop aborts
|
// In case a TransactionException is thrown this loop aborts
|
||||||
final long assigned = assignTargetsToGroupInNewTransaction(rollout, group, groupTargetFilter,
|
final long assigned = assignTargetsToGroupInNewTransaction(
|
||||||
Math.min(TRANSACTION_TARGETS, targetsLeftToAdd));
|
rollout, group, groupTargetFilter, Math.min(TRANSACTION_TARGETS, targetsLeftToAdd));
|
||||||
if (assigned == 0) {
|
if (assigned == 0) {
|
||||||
break; // percent > 100 or some could have disappeared
|
break; // percent > 100 or some could have disappeared
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -357,8 +357,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
final List<RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupSuccessCondition>> successConditionEvaluators,
|
final List<RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupSuccessCondition>> successConditionEvaluators,
|
||||||
final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupErrorAction>> errorActionEvaluators,
|
final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupErrorAction>> errorActionEvaluators,
|
||||||
final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupSuccessAction>> successActionEvaluators) {
|
final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupSuccessAction>> successActionEvaluators) {
|
||||||
return new RolloutGroupEvaluationManager(errorConditionEvaluators, successConditionEvaluators,
|
return new RolloutGroupEvaluationManager(
|
||||||
errorActionEvaluators, successActionEvaluators);
|
errorConditionEvaluators, successConditionEvaluators, errorActionEvaluators, successActionEvaluators);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -696,8 +696,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
final DistributionSetTagRepository distributionSetTagRepository,
|
final DistributionSetTagRepository distributionSetTagRepository,
|
||||||
final DistributionSetRepository distributionSetRepository,
|
final DistributionSetRepository distributionSetRepository,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties) {
|
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties) {
|
||||||
return new JpaDistributionSetTagManagement(distributionSetTagRepository, distributionSetRepository,
|
return new JpaDistributionSetTagManagement(
|
||||||
virtualPropertyReplacer, properties.getDatabase());
|
distributionSetTagRepository, distributionSetRepository, virtualPropertyReplacer, properties.getDatabase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -735,8 +735,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
final SoftwareModuleRepository softwareModuleRepository,
|
final SoftwareModuleRepository softwareModuleRepository,
|
||||||
final JpaProperties properties) {
|
final JpaProperties properties) {
|
||||||
return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
|
return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
|
||||||
virtualPropertyReplacer, softwareModuleRepository,
|
virtualPropertyReplacer, softwareModuleRepository, properties.getDatabase());
|
||||||
properties.getDatabase());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -744,8 +743,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
RolloutHandler rolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
|
RolloutHandler rolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
|
||||||
final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry,
|
final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry,
|
||||||
final PlatformTransactionManager txManager, final ContextAware contextAware) {
|
final PlatformTransactionManager txManager, final ContextAware contextAware) {
|
||||||
return new JpaRolloutHandler(tenantAware, rolloutManagement, rolloutExecutor, lockRegistry, txManager,
|
return new JpaRolloutHandler(tenantAware, rolloutManagement, rolloutExecutor, lockRegistry, txManager, contextAware);
|
||||||
contextAware);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -777,8 +775,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
final ContextAware contextAware) {
|
final ContextAware contextAware) {
|
||||||
return new JpaRolloutManagement(targetManagement, distributionSetManagement, eventPublisherHolder,
|
return new JpaRolloutManagement(targetManagement, distributionSetManagement, eventPublisherHolder,
|
||||||
virtualPropertyReplacer, properties.getDatabase(), rolloutApprovalStrategy,
|
virtualPropertyReplacer, properties.getDatabase(), rolloutApprovalStrategy,
|
||||||
tenantConfigurationManagement, systemSecurityContext,
|
tenantConfigurationManagement, systemSecurityContext, contextAware);
|
||||||
contextAware);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -860,10 +857,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
ArtifactManagement artifactManagement(
|
ArtifactManagement artifactManagement(
|
||||||
final EntityManager entityManager, final LocalArtifactRepository localArtifactRepository,
|
final EntityManager entityManager, final PlatformTransactionManager txManager,
|
||||||
final SoftwareModuleRepository softwareModuleRepository, final Optional<ArtifactRepository> artifactRepository,
|
final LocalArtifactRepository localArtifactRepository, final SoftwareModuleRepository softwareModuleRepository,
|
||||||
|
final Optional<ArtifactRepository> artifactRepository,
|
||||||
final QuotaManagement quotaManagement, final TenantAware tenantAware) {
|
final QuotaManagement quotaManagement, final TenantAware tenantAware) {
|
||||||
return new JpaArtifactManagement(entityManager, localArtifactRepository, softwareModuleRepository, artifactRepository.orElse(null),
|
return new JpaArtifactManagement(
|
||||||
|
entityManager, txManager, localArtifactRepository, softwareModuleRepository, artifactRepository.orElse(null),
|
||||||
quotaManagement, tenantAware);
|
quotaManagement, tenantAware);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
|
import org.springframework.transaction.support.TransactionSynchronization;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Service which calls register runnable. This runnables will executed after a
|
* A Service which calls register runnable. This runnables will be executed after a successful spring transaction commit.
|
||||||
* successful spring transaction commit.The class is thread safe.
|
* The class is thread safe.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSynchronizationAdapter implements AfterTransactionCommitExecutor {
|
public class AfterTransactionCommitDefaultServiceExecutor implements TransactionSynchronization, AfterTransactionCommitExecutor {
|
||||||
|
|
||||||
private static final ThreadLocal<List<Runnable>> THREAD_LOCAL_RUNNABLES = new ThreadLocal<>();
|
private static final ThreadLocal<List<Runnable>> THREAD_LOCAL_RUNNABLES = new ThreadLocal<>();
|
||||||
|
|
||||||
@@ -30,6 +30,14 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn
|
|||||||
@SuppressWarnings({ "squid:S1217" })
|
@SuppressWarnings({ "squid:S1217" })
|
||||||
public void afterCommit() {
|
public void afterCommit() {
|
||||||
final List<Runnable> afterCommitRunnables = THREAD_LOCAL_RUNNABLES.get();
|
final List<Runnable> afterCommitRunnables = THREAD_LOCAL_RUNNABLES.get();
|
||||||
|
if (afterCommitRunnables == null) {
|
||||||
|
log.trace("Transaction successfully committed, runnables is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// removes the runnables that will process, so they would be able to start new transactions and
|
||||||
|
// inserting new after commit hooks
|
||||||
|
THREAD_LOCAL_RUNNABLES.remove();
|
||||||
log.debug("Transaction successfully committed, executing {} runnables", afterCommitRunnables.size());
|
log.debug("Transaction successfully committed, executing {} runnables", afterCommitRunnables.size());
|
||||||
for (final Runnable afterCommitRunnable : afterCommitRunnables) {
|
for (final Runnable afterCommitRunnable : afterCommitRunnables) {
|
||||||
log.debug("Executing runnable {}", afterCommitRunnable);
|
log.debug("Executing runnable {}", afterCommitRunnable);
|
||||||
@@ -44,8 +52,7 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "squid:S1217" })
|
@SuppressWarnings({ "squid:S1217" })
|
||||||
public void afterCompletion(final int status) {
|
public void afterCompletion(final int status) {
|
||||||
final String transactionStatus = status == STATUS_COMMITTED ? "COMMITTED" : "ROLLEDBACK";
|
log.debug("Transaction completed after commit with status {}", status == STATUS_COMMITTED ? "COMMITTED" : "ROLLEDBACK");
|
||||||
log.debug("Transaction completed after commit with status {}", transactionStatus);
|
|
||||||
THREAD_LOCAL_RUNNABLES.remove();
|
THREAD_LOCAL_RUNNABLES.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,26 +36,31 @@ import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
|||||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA256HashException;
|
import org.eclipse.hawkbit.repository.exception.InvalidSHA256HashException;
|
||||||
import org.eclipse.hawkbit.repository.jpa.EncryptionAwareDbArtifact;
|
import org.eclipse.hawkbit.repository.jpa.EncryptionAwareDbArtifact;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.Jpa;
|
||||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.specifications.ArtifactSpecifications;
|
import org.eclipse.hawkbit.repository.jpa.specifications.ArtifactSpecifications;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||||
import org.eclipse.hawkbit.repository.jpa.utils.FileSizeAndStorageQuotaCheckingInputStream;
|
import org.eclipse.hawkbit.repository.jpa.utils.FileSizeAndStorageQuotaCheckingInputStream;
|
||||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.dao.ConcurrencyFailureException;
|
import org.springframework.dao.ConcurrencyFailureException;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.retry.annotation.Backoff;
|
import org.springframework.retry.annotation.Backoff;
|
||||||
import org.springframework.retry.annotation.Retryable;
|
import org.springframework.retry.annotation.Retryable;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionSynchronization;
|
import org.springframework.transaction.support.TransactionSynchronization;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
@@ -70,6 +75,7 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
public class JpaArtifactManagement implements ArtifactManagement {
|
public class JpaArtifactManagement implements ArtifactManagement {
|
||||||
|
|
||||||
private final EntityManager entityManager;
|
private final EntityManager entityManager;
|
||||||
|
private final PlatformTransactionManager txManager;
|
||||||
private final LocalArtifactRepository localArtifactRepository;
|
private final LocalArtifactRepository localArtifactRepository;
|
||||||
private final SoftwareModuleRepository softwareModuleRepository;
|
private final SoftwareModuleRepository softwareModuleRepository;
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -79,10 +85,13 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
|
|
||||||
public JpaArtifactManagement(
|
public JpaArtifactManagement(
|
||||||
final EntityManager entityManager,
|
final EntityManager entityManager,
|
||||||
|
final PlatformTransactionManager txManager,
|
||||||
final LocalArtifactRepository localArtifactRepository,
|
final LocalArtifactRepository localArtifactRepository,
|
||||||
final SoftwareModuleRepository softwareModuleRepository, @Nullable final ArtifactRepository artifactRepository,
|
final SoftwareModuleRepository softwareModuleRepository, @Nullable final ArtifactRepository artifactRepository,
|
||||||
final QuotaManagement quotaManagement, final TenantAware tenantAware) {
|
final QuotaManagement quotaManagement,
|
||||||
|
final TenantAware tenantAware) {
|
||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
|
this.txManager = txManager;
|
||||||
this.localArtifactRepository = localArtifactRepository;
|
this.localArtifactRepository = localArtifactRepository;
|
||||||
this.softwareModuleRepository = softwareModuleRepository;
|
this.softwareModuleRepository = softwareModuleRepository;
|
||||||
this.artifactRepository = artifactRepository;
|
this.artifactRepository = artifactRepository;
|
||||||
@@ -137,18 +146,19 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public void delete(final long id) {
|
public void delete(final long id) {
|
||||||
final JpaArtifact toDelete = (JpaArtifact) get(id)
|
final JpaArtifact toDelete = (JpaArtifact) get(id).orElseThrow(() -> new EntityNotFoundException(Artifact.class, id));
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Artifact.class, id));
|
|
||||||
|
|
||||||
|
final JpaSoftwareModule softwareModule = toDelete.getSoftwareModule();
|
||||||
// clearArtifactBinary checks (unconditionally) software module UPDATE access
|
// clearArtifactBinary checks (unconditionally) software module UPDATE access
|
||||||
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
||||||
accessController.assertOperationAllowed(AccessController.Operation.UPDATE,
|
accessController.assertOperationAllowed(AccessController.Operation.UPDATE, softwareModule));
|
||||||
(JpaSoftwareModule) toDelete.getSoftwareModule()));
|
softwareModule.removeArtifact(toDelete);
|
||||||
((JpaSoftwareModule) toDelete.getSoftwareModule()).removeArtifact(toDelete);
|
softwareModuleRepository.save(softwareModule);
|
||||||
softwareModuleRepository.save((JpaSoftwareModule) toDelete.getSoftwareModule());
|
|
||||||
|
|
||||||
localArtifactRepository.deleteById(id);
|
localArtifactRepository.deleteById(id);
|
||||||
clearArtifactBinary(toDelete.getSha1Hash());
|
|
||||||
|
final String sha1Hash = toDelete.getSha1Hash();
|
||||||
|
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> clearArtifactBinary(sha1Hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -211,39 +221,35 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Garbage collects artifact binaries if only referenced by given
|
* Garbage collects artifact binaries if only referenced by given {@link SoftwareModule#getId()} or {@link SoftwareModule}'s that are
|
||||||
* {@link SoftwareModule#getId()} or {@link SoftwareModule}'s that are
|
|
||||||
* marked as deleted.
|
* marked as deleted.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Software module related UPDATE permission shall be checked by the callers!
|
* Software module related UPDATE permission shall be checked by the callers!
|
||||||
|
* <p/>
|
||||||
|
* Note: Internal method. Shall be called ONLY if @PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||||
|
* has already been checked
|
||||||
*
|
*
|
||||||
* @param sha1Hash no longer needed
|
* @param sha1Hash no longer needed
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
|
||||||
void clearArtifactBinary(final String sha1Hash) {
|
void clearArtifactBinary(final String sha1Hash) {
|
||||||
assertArtifactRepositoryAvailable();
|
assertArtifactRepositoryAvailable();
|
||||||
|
|
||||||
// countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse will skip ACM checks and
|
DeploymentHelper.runInNewTransaction(txManager, "clearArtifactBinary", status -> {
|
||||||
// will return total count as it should be
|
// countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse will skip ACM checks and will return total count as it should be
|
||||||
final long count = localArtifactRepository.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(
|
if (localArtifactRepository.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(sha1Hash, tenantAware.getCurrentTenant()) <= 0) { // 1 artifact is the one being deleted!
|
||||||
sha1Hash,
|
|
||||||
tenantAware.getCurrentTenant());
|
|
||||||
if (count <= 1) { // 1 artifact is the one being deleted!
|
|
||||||
// removes the real artifact ONLY AFTER the delete of artifact or software module
|
// removes the real artifact ONLY AFTER the delete of artifact or software module
|
||||||
// in local history has passed successfully (caller has permission and no errors)
|
// in local history has passed successfully (caller has permission and no errors)
|
||||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCommit() {
|
|
||||||
try {
|
try {
|
||||||
log.debug("deleting artifact from repository {}", sha1Hash);
|
log.debug("deleting artifact from repository {}", sha1Hash);
|
||||||
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), sha1Hash);
|
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), sha1Hash);
|
||||||
} catch (final ArtifactStoreException e) {
|
} catch (final ArtifactStoreException e) {
|
||||||
throw new ArtifactDeleteFailedException(e);
|
throw new ArtifactDeleteFailedException(e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} // else there are still other artifacts that need the binary
|
} // else there are still other artifacts that need the binary
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload, final boolean isSmEncrypted) {
|
private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload, final boolean isSmEncrypted) {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
|||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey;
|
import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||||
@@ -199,10 +200,6 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
|
|
||||||
final Set<Long> assignedModuleIds = new HashSet<>();
|
final Set<Long> assignedModuleIds = new HashSet<>();
|
||||||
swModulesToDelete.forEach(swModule -> {
|
swModulesToDelete.forEach(swModule -> {
|
||||||
|
|
||||||
// delete binary data of artifacts
|
|
||||||
deleteGridFsArtifacts(swModule);
|
|
||||||
|
|
||||||
// execute this count operation without access limitations since we have to
|
// execute this count operation without access limitations since we have to
|
||||||
// ensure it's not assigned when deleting it.
|
// ensure it's not assigned when deleting it.
|
||||||
if (distributionSetRepository.countByModulesId(swModule.getId()) <= 0) {
|
if (distributionSetRepository.countByModulesId(swModule.getId()) <= 0) {
|
||||||
@@ -210,6 +207,8 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
} else {
|
} else {
|
||||||
assignedModuleIds.add(swModule.getId());
|
assignedModuleIds.add(swModule.getId());
|
||||||
}
|
}
|
||||||
|
// schedule delete binary data of artifacts
|
||||||
|
deleteGridFsArtifacts(swModule);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!assignedModuleIds.isEmpty()) {
|
if (!assignedModuleIds.isEmpty()) {
|
||||||
@@ -507,10 +506,9 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
|||||||
private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) {
|
private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) {
|
||||||
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
||||||
accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
||||||
for (final Artifact localArtifact : swModule.getArtifacts()) {
|
final Set<String> sha1Hashes = swModule.getArtifacts().stream().map(Artifact::getSha1Hash).collect(Collectors.toSet());
|
||||||
((JpaArtifactManagement) artifactManagement)
|
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() ->
|
||||||
.clearArtifactBinary(localArtifact.getSha1Hash());
|
sha1Hashes.forEach(sha1Hash -> ((JpaArtifactManagement) artifactManagement).clearArtifactBinary(sha1Hash)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Specification<JpaSoftwareModule> buildSmSearchQuerySpec(final String searchText) {
|
private Specification<JpaSoftwareModule> buildSmSearchQuerySpec(final String searchText) {
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
|||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
||||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetMetadataRepository;
|
import org.eclipse.hawkbit.repository.jpa.repository.TargetMetadataRepository;
|
||||||
@@ -648,15 +649,20 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||||
|
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public void requestControllerAttributes(final String controllerId) {
|
public void requestControllerAttributes(final String controllerId) {
|
||||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||||
targetRepository.getAccessController()
|
targetRepository.getAccessController()
|
||||||
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, target));
|
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, target));
|
||||||
target.setRequestControllerAttributes(true);
|
target.setRequestControllerAttributes(true);
|
||||||
|
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() ->
|
||||||
eventPublisherHolder.getEventPublisher()
|
eventPublisherHolder.getEventPublisher()
|
||||||
.publishEvent(new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(),
|
.publishEvent(new TargetAttributesRequestedEvent(
|
||||||
target.getControllerId(), target.getAddress() != null ? target.getAddress().toString() : null,
|
tenantAware.getCurrentTenant(), target.getId(), target.getControllerId(),
|
||||||
JpaTarget.class, eventPublisherHolder.getApplicationId()));
|
target.getAddress() != null ? target.getAddress().toString() : null,
|
||||||
|
JpaTarget.class, eventPublisherHolder.getApplicationId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -718,14 +724,12 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
final JpaTarget updatedTarget = JpaManagementHelper.touch(entityManager, targetRepository, target);
|
final JpaTarget updatedTarget = JpaManagementHelper.touch(entityManager, targetRepository, target);
|
||||||
|
|
||||||
final List<TargetMetadata> createdMetadata = md.stream()
|
final List<TargetMetadata> createdMetadata = md.stream()
|
||||||
.map(meta -> targetMetadataRepository
|
.map(meta -> targetMetadataRepository.save(new JpaTargetMetadata(meta.getKey(), meta.getValue(), updatedTarget)))
|
||||||
.save(new JpaTargetMetadata(meta.getKey(), meta.getValue(), updatedTarget)))
|
|
||||||
.collect(Collectors.toUnmodifiableList());
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
|
||||||
// TargetUpdatedEvent is not sent within the touch() method due to the
|
// TargetUpdatedEvent is not sent within the touch() method due to the
|
||||||
// "lastModifiedAt" field being ignored in JpaTarget
|
// "lastModifiedAt" field being ignored in JpaTarget
|
||||||
eventPublisherHolder.getEventPublisher()
|
eventPublisherHolder.getEventPublisher().publishEvent(new TargetUpdatedEvent(updatedTarget, eventPublisherHolder.getApplicationId()));
|
||||||
.publishEvent(new TargetUpdatedEvent(updatedTarget, eventPublisherHolder.getApplicationId()));
|
|
||||||
|
|
||||||
return createdMetadata;
|
return createdMetadata;
|
||||||
}
|
}
|
||||||
@@ -738,8 +742,8 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
final JpaTargetMetadata metadata = (JpaTargetMetadata) getMetaDataByControllerId(controllerId, key)
|
final JpaTargetMetadata metadata = (JpaTargetMetadata) getMetaDataByControllerId(controllerId, key)
|
||||||
.orElseThrow(() -> new EntityNotFoundException(TargetMetadata.class, controllerId, key));
|
.orElseThrow(() -> new EntityNotFoundException(TargetMetadata.class, controllerId, key));
|
||||||
|
|
||||||
final JpaTarget target = JpaManagementHelper.touch(entityManager, targetRepository,
|
final JpaTarget target = JpaManagementHelper.touch(
|
||||||
getByControllerIdAndThrowIfNotFound(controllerId));
|
entityManager, targetRepository, getByControllerIdAndThrowIfNotFound(controllerId));
|
||||||
|
|
||||||
targetRepository.getAccessController()
|
targetRepository.getAccessController()
|
||||||
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, target));
|
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, target));
|
||||||
|
|||||||
@@ -64,12 +64,12 @@ import org.junit.jupiter.api.Test;
|
|||||||
*/
|
*/
|
||||||
@Feature("Component Tests - Repository")
|
@Feature("Component Tests - Repository")
|
||||||
@Story("Artifact Management")
|
@Story("Artifact Management")
|
||||||
public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that management get access react as specfied on calls for non existing entities by means of Optional not present.")
|
@Description("Verifies that management get access react as specfied on calls for non existing entities by means of Optional not present.")
|
||||||
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
||||||
public void nonExistingEntityAccessReturnsNotPresent() {
|
void nonExistingEntityAccessReturnsNotPresent() {
|
||||||
final SoftwareModule module = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule module = testdataFactory.createSoftwareModuleOs();
|
||||||
|
|
||||||
assertThat(artifactManagement.get(NOT_EXIST_IDL)).isNotPresent();
|
assertThat(artifactManagement.get(NOT_EXIST_IDL)).isNotPresent();
|
||||||
@@ -85,7 +85,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Description("Verifies that management queries react as specfied on calls for non existing entities "
|
@Description("Verifies that management queries react as specfied on calls for non existing entities "
|
||||||
+ " by means of throwing EntityNotFoundException.")
|
+ " by means of throwing EntityNotFoundException.")
|
||||||
@ExpectEvents({ @Expect(type = SoftwareModuleDeletedEvent.class, count = 0) })
|
@ExpectEvents({ @Expect(type = SoftwareModuleDeletedEvent.class, count = 0) })
|
||||||
public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws URISyntaxException {
|
void entityQueriesReferringToNotExistingEntitiesThrowsException() throws URISyntaxException {
|
||||||
|
|
||||||
final String artifactData = "test";
|
final String artifactData = "test";
|
||||||
final int artifactSize = artifactData.length();
|
final int artifactSize = artifactData.length();
|
||||||
@@ -110,7 +110,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Test if a local artifact can be created by API including metadata.")
|
@Description("Test if a local artifact can be created by API including metadata.")
|
||||||
public void createArtifact() throws IOException {
|
void createArtifact() throws IOException {
|
||||||
|
|
||||||
// check baseline
|
// check baseline
|
||||||
assertThat(softwareModuleRepository.findAll()).hasSize(0);
|
assertThat(softwareModuleRepository.findAll()).hasSize(0);
|
||||||
@@ -161,7 +161,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that artifact management does not create artifacts with illegal filename.")
|
@Description("Verifies that artifact management does not create artifacts with illegal filename.")
|
||||||
public void entityQueryWithIllegalFilenameThrowsException() throws URISyntaxException {
|
void entityQueryWithIllegalFilenameThrowsException() throws URISyntaxException {
|
||||||
final String illegalFilename = "<img src=ernw onerror=alert(1)>.xml";
|
final String illegalFilename = "<img src=ernw onerror=alert(1)>.xml";
|
||||||
final String artifactData = "test";
|
final String artifactData = "test";
|
||||||
final int artifactSize = artifactData.length();
|
final int artifactSize = artifactData.length();
|
||||||
@@ -176,7 +176,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that the quota specifying the maximum number of artifacts per software module is enforced.")
|
@Description("Verifies that the quota specifying the maximum number of artifacts per software module is enforced.")
|
||||||
public void createArtifactsUntilQuotaIsExceeded() throws IOException {
|
void createArtifactsUntilQuotaIsExceeded() throws IOException {
|
||||||
// create a software module
|
// create a software module
|
||||||
final long smId = softwareModuleRepository.save(new JpaSoftwareModule(osType, "sm1", "1.0")).getId();
|
final long smId = softwareModuleRepository.save(new JpaSoftwareModule(osType, "sm1", "1.0")).getId();
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that the quota specifying the maximum artifact storage is enforced (across software modules).")
|
@Description("Verifies that the quota specifying the maximum artifact storage is enforced (across software modules).")
|
||||||
public void createArtifactsUntilStorageQuotaIsExceeded() throws IOException {
|
void createArtifactsUntilStorageQuotaIsExceeded() throws IOException {
|
||||||
|
|
||||||
// create as many small artifacts as possible w/o violating the storage
|
// create as many small artifacts as possible w/o violating the storage
|
||||||
// quota
|
// quota
|
||||||
@@ -235,7 +235,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that you cannot create artifacts which exceed the configured maximum size.")
|
@Description("Verifies that you cannot create artifacts which exceed the configured maximum size.")
|
||||||
public void createArtifactFailsIfTooLarge() {
|
void createArtifactFailsIfTooLarge() {
|
||||||
|
|
||||||
// create a software module
|
// create a software module
|
||||||
final JpaSoftwareModule sm1 = softwareModuleRepository.save(new JpaSoftwareModule(osType, "sm1", "1.0"));
|
final JpaSoftwareModule sm1 = softwareModuleRepository.save(new JpaSoftwareModule(osType, "sm1", "1.0"));
|
||||||
@@ -248,7 +248,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Tests hard delete directly on repository.")
|
@Description("Tests hard delete directly on repository.")
|
||||||
public void hardDeleteSoftwareModule() throws IOException {
|
void hardDeleteSoftwareModule() throws IOException {
|
||||||
|
|
||||||
final JpaSoftwareModule sm = softwareModuleRepository
|
final JpaSoftwareModule sm = softwareModuleRepository
|
||||||
.save(new JpaSoftwareModule(osType, "name 1", "version 1"));
|
.save(new JpaSoftwareModule(osType, "name 1", "version 1"));
|
||||||
@@ -268,7 +268,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@Description("Tests the deletion of a local artifact including metadata.")
|
@Description("Tests the deletion of a local artifact including metadata.")
|
||||||
public void deleteArtifact() throws IOException {
|
void deleteArtifact() throws IOException {
|
||||||
final JpaSoftwareModule sm = softwareModuleRepository
|
final JpaSoftwareModule sm = softwareModuleRepository
|
||||||
.save(new JpaSoftwareModule(osType, "name 1", "version 1"));
|
.save(new JpaSoftwareModule(osType, "name 1", "version 1"));
|
||||||
final JpaSoftwareModule sm2 = softwareModuleRepository
|
final JpaSoftwareModule sm2 = softwareModuleRepository
|
||||||
@@ -320,7 +320,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Description("Test the deletion of an artifact metadata where the binary is still linked to another metadata element. " +
|
@Description("Test the deletion of an artifact metadata where the binary is still linked to another metadata element. " +
|
||||||
"The expected result is that the metadata is deleted but the binary kept.")
|
"The expected result is that the metadata is deleted but the binary kept.")
|
||||||
public void deleteDuplicateArtifacts() throws IOException {
|
void deleteDuplicateArtifacts() throws IOException {
|
||||||
final JpaSoftwareModule sm = softwareModuleRepository
|
final JpaSoftwareModule sm = softwareModuleRepository
|
||||||
.save(new JpaSoftwareModule(osType, "name 1", "version 1"));
|
.save(new JpaSoftwareModule(osType, "name 1", "version 1"));
|
||||||
final JpaSoftwareModule sm2 = softwareModuleRepository
|
final JpaSoftwareModule sm2 = softwareModuleRepository
|
||||||
@@ -353,7 +353,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that you cannot delete an artifact which exists with the same hash, in the same tenant and the SoftwareModule is not deleted .")
|
@Description("Verifies that you cannot delete an artifact which exists with the same hash, in the same tenant and the SoftwareModule is not deleted .")
|
||||||
public void deleteArtifactWithSameHashAndSoftwareModuleIsNotDeletedInSameTenants() throws IOException {
|
void deleteArtifactWithSameHashAndSoftwareModuleIsNotDeletedInSameTenants() throws IOException {
|
||||||
|
|
||||||
final JpaSoftwareModule sm = softwareModuleRepository
|
final JpaSoftwareModule sm = softwareModuleRepository
|
||||||
.save(new JpaSoftwareModule(osType, "name 1", "version 1"));
|
.save(new JpaSoftwareModule(osType, "name 1", "version 1"));
|
||||||
@@ -395,7 +395,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that you can not delete artifacts from another tenant which exists in another tenant with the same hash and the SoftwareModule is not deleted")
|
@Description("Verifies that you can not delete artifacts from another tenant which exists in another tenant with the same hash and the SoftwareModule is not deleted")
|
||||||
public void deleteArtifactWithSameHashAndSoftwareModuleIsNotDeletedInDifferentTenants() throws Exception {
|
void deleteArtifactWithSameHashAndSoftwareModuleIsNotDeletedInDifferentTenants() throws Exception {
|
||||||
final String tenant1 = "mytenant";
|
final String tenant1 = "mytenant";
|
||||||
final String tenant2 = "tenant2";
|
final String tenant2 = "tenant2";
|
||||||
|
|
||||||
@@ -422,7 +422,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Loads an local artifact based on given ID.")
|
@Description("Loads an local artifact based on given ID.")
|
||||||
public void findArtifact() throws IOException {
|
void findArtifact() throws IOException {
|
||||||
final int artifactSize = 5 * 1024;
|
final int artifactSize = 5 * 1024;
|
||||||
try (final InputStream inputStream = new RandomGeneratedInputStream(artifactSize)) {
|
try (final InputStream inputStream = new RandomGeneratedInputStream(artifactSize)) {
|
||||||
final Artifact artifact = createArtifactForSoftwareModule(
|
final Artifact artifact = createArtifactForSoftwareModule(
|
||||||
@@ -433,7 +433,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Loads an artifact binary based on given ID.")
|
@Description("Loads an artifact binary based on given ID.")
|
||||||
public void loadStreamOfArtifact() throws IOException {
|
void loadStreamOfArtifact() throws IOException {
|
||||||
final int artifactSize = 5 * 1024;
|
final int artifactSize = 5 * 1024;
|
||||||
final byte[] randomBytes = randomBytes(artifactSize);
|
final byte[] randomBytes = randomBytes(artifactSize);
|
||||||
try (final InputStream input = new ByteArrayInputStream(randomBytes)) {
|
try (final InputStream input = new ByteArrayInputStream(randomBytes)) {
|
||||||
@@ -448,7 +448,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@WithUser(allSpPermissions = true, removeFromAllPermission = { SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT })
|
@WithUser(allSpPermissions = true, removeFromAllPermission = { SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT })
|
||||||
@Description("Trys and fails to load an artifact without required permission. Checks if expected InsufficientPermissionException is thrown.")
|
@Description("Trys and fails to load an artifact without required permission. Checks if expected InsufficientPermissionException is thrown.")
|
||||||
public void loadArtifactBinaryWithoutDownloadArtifactThrowsPermissionDenied() {
|
void loadArtifactBinaryWithoutDownloadArtifactThrowsPermissionDenied() {
|
||||||
assertThatExceptionOfType(InsufficientPermissionException.class)
|
assertThatExceptionOfType(InsufficientPermissionException.class)
|
||||||
.as("Should not have worked with missing permission.")
|
.as("Should not have worked with missing permission.")
|
||||||
.isThrownBy(() -> artifactManagement.loadArtifactBinary("123", 1, false));
|
.isThrownBy(() -> artifactManagement.loadArtifactBinary("123", 1, false));
|
||||||
@@ -456,7 +456,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Searches an artifact through the relations of a software module.")
|
@Description("Searches an artifact through the relations of a software module.")
|
||||||
public void findArtifactBySoftwareModule() throws IOException {
|
void findArtifactBySoftwareModule() throws IOException {
|
||||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||||
assertThat(artifactManagement.findBySoftwareModule(PAGE, sm.getId())).isEmpty();
|
assertThat(artifactManagement.findBySoftwareModule(PAGE, sm.getId())).isEmpty();
|
||||||
|
|
||||||
@@ -469,7 +469,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Searches an artifact through the relations of a software module and the filename.")
|
@Description("Searches an artifact through the relations of a software module and the filename.")
|
||||||
public void findByFilenameAndSoftwareModule() throws IOException {
|
void findByFilenameAndSoftwareModule() throws IOException {
|
||||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||||
|
|
||||||
assertThat(artifactManagement.getByFilenameAndSoftwareModule("file1", sm.getId())).isNotPresent();
|
assertThat(artifactManagement.getByFilenameAndSoftwareModule("file1", sm.getId())).isNotPresent();
|
||||||
@@ -485,7 +485,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that creation of an artifact with none matching hashes fails.")
|
@Description("Verifies that creation of an artifact with none matching hashes fails.")
|
||||||
public void createArtifactWithNoneMatchingHashes() throws IOException, NoSuchAlgorithmException {
|
void createArtifactWithNoneMatchingHashes() throws IOException, NoSuchAlgorithmException {
|
||||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||||
|
|
||||||
final byte[] testData = RandomStringUtils.randomAlphanumeric(100).getBytes();
|
final byte[] testData = RandomStringUtils.randomAlphanumeric(100).getBytes();
|
||||||
@@ -517,7 +517,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that creation of an artifact with matching hashes works.")
|
@Description("Verifies that creation of an artifact with matching hashes works.")
|
||||||
public void createArtifactWithMatchingHashes() throws IOException, NoSuchAlgorithmException {
|
void createArtifactWithMatchingHashes() throws IOException, NoSuchAlgorithmException {
|
||||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||||
|
|
||||||
final byte[] testData = RandomStringUtils.randomAlphanumeric(100).getBytes();
|
final byte[] testData = RandomStringUtils.randomAlphanumeric(100).getBytes();
|
||||||
@@ -540,7 +540,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that creation of an existing artifact returns a full hash list.")
|
@Description("Verifies that creation of an existing artifact returns a full hash list.")
|
||||||
public void createExistingArtifactReturnsFullHashList() throws IOException, NoSuchAlgorithmException {
|
void createExistingArtifactReturnsFullHashList() throws IOException, NoSuchAlgorithmException {
|
||||||
final SoftwareModule smOs = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule smOs = testdataFactory.createSoftwareModuleOs();
|
||||||
final SoftwareModule smApp = testdataFactory.createSoftwareModuleApp();
|
final SoftwareModule smApp = testdataFactory.createSoftwareModuleApp();
|
||||||
|
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ import org.springframework.data.domain.PageRequest;
|
|||||||
|
|
||||||
@Feature("Component Tests - Repository")
|
@Feature("Component Tests - Repository")
|
||||||
@Story("Software Module Management")
|
@Story("Software Module Management")
|
||||||
public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that management get access reacts as specified on calls for non existing entities by means "
|
@Description("Verifies that management get access reacts as specified on calls for non existing entities by means "
|
||||||
+ "of Optional not present.")
|
+ "of Optional not present.")
|
||||||
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
||||||
public void nonExistingEntityAccessReturnsNotPresent() {
|
void nonExistingEntityAccessReturnsNotPresent() {
|
||||||
final SoftwareModule module = testdataFactory.createSoftwareModuleApp();
|
final SoftwareModule module = testdataFactory.createSoftwareModuleApp();
|
||||||
|
|
||||||
assertThat(softwareModuleManagement.get(1234L)).isNotPresent();
|
assertThat(softwareModuleManagement.get(1234L)).isNotPresent();
|
||||||
@@ -78,7 +78,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Description("Verifies that management queries react as specfied on calls for non existing entities "
|
@Description("Verifies that management queries react as specfied on calls for non existing entities "
|
||||||
+ " by means of throwing EntityNotFoundException.")
|
+ " by means of throwing EntityNotFoundException.")
|
||||||
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
@ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) })
|
||||||
public void entityQueriesReferringToNotExistingEntitiesThrowsException() {
|
void entityQueriesReferringToNotExistingEntitiesThrowsException() {
|
||||||
final SoftwareModule module = testdataFactory.createSoftwareModuleApp();
|
final SoftwareModule module = testdataFactory.createSoftwareModuleApp();
|
||||||
|
|
||||||
verifyThrownExceptionBy(
|
verifyThrownExceptionBy(
|
||||||
@@ -138,7 +138,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Calling update without changing fields results in no recorded change in the repository including unchanged audit fields.")
|
@Description("Calling update without changing fields results in no recorded change in the repository including unchanged audit fields.")
|
||||||
public void updateNothingResultsInUnchangedRepository() {
|
void updateNothingResultsInUnchangedRepository() {
|
||||||
final SoftwareModule ah = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule ah = testdataFactory.createSoftwareModuleOs();
|
||||||
|
|
||||||
final SoftwareModule updated = softwareModuleManagement
|
final SoftwareModule updated = softwareModuleManagement
|
||||||
@@ -151,7 +151,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Calling update for changed fields results in change in the repository.")
|
@Description("Calling update for changed fields results in change in the repository.")
|
||||||
public void updateSoftwareModuleFieldsToNewValue() {
|
void updateSoftwareModuleFieldsToNewValue() {
|
||||||
final SoftwareModule ah = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule ah = testdataFactory.createSoftwareModuleOs();
|
||||||
|
|
||||||
final SoftwareModule updated = softwareModuleManagement
|
final SoftwareModule updated = softwareModuleManagement
|
||||||
@@ -166,7 +166,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Create Software Module call fails when called for existing entity.")
|
@Description("Create Software Module call fails when called for existing entity.")
|
||||||
public void createModuleCallFailsForExistingModule() {
|
void createModuleCallFailsForExistingModule() {
|
||||||
testdataFactory.createSoftwareModuleOs();
|
testdataFactory.createSoftwareModuleOs();
|
||||||
assertThatExceptionOfType(EntityAlreadyExistsException.class)
|
assertThatExceptionOfType(EntityAlreadyExistsException.class)
|
||||||
.as("Should not have worked as module already exists.")
|
.as("Should not have worked as module already exists.")
|
||||||
@@ -175,7 +175,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("searched for software modules based on the various filter options, e.g. name,desc,type, version.")
|
@Description("searched for software modules based on the various filter options, e.g. name,desc,type, version.")
|
||||||
public void findSoftwareModuleByFilters() {
|
void findSoftwareModuleByFilters() {
|
||||||
final SoftwareModule ah = softwareModuleManagement
|
final SoftwareModule ah = softwareModuleManagement
|
||||||
.create(entityFactory.softwareModule().create().type(appType).name("agent-hub").version("1.0.1"));
|
.create(entityFactory.softwareModule().create().type(appType).name("agent-hub").version("1.0.1"));
|
||||||
final SoftwareModule jvm = softwareModuleManagement
|
final SoftwareModule jvm = softwareModuleManagement
|
||||||
@@ -217,7 +217,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Searches for software modules based on a list of IDs.")
|
@Description("Searches for software modules based on a list of IDs.")
|
||||||
public void findSoftwareModulesById() {
|
void findSoftwareModulesById() {
|
||||||
|
|
||||||
final List<Long> modules = Arrays.asList(testdataFactory.createSoftwareModuleOs().getId(),
|
final List<Long> modules = Arrays.asList(testdataFactory.createSoftwareModuleOs().getId(),
|
||||||
testdataFactory.createSoftwareModuleApp().getId(), 624355263L);
|
testdataFactory.createSoftwareModuleApp().getId(), 624355263L);
|
||||||
@@ -227,7 +227,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Searches for software modules by type.")
|
@Description("Searches for software modules by type.")
|
||||||
public void findSoftwareModulesByType() {
|
void findSoftwareModulesByType() {
|
||||||
// found in test
|
// found in test
|
||||||
final SoftwareModule one = testdataFactory.createSoftwareModuleOs("one");
|
final SoftwareModule one = testdataFactory.createSoftwareModuleOs("one");
|
||||||
final SoftwareModule two = testdataFactory.createSoftwareModuleOs("two");
|
final SoftwareModule two = testdataFactory.createSoftwareModuleOs("two");
|
||||||
@@ -242,7 +242,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Counts all software modules in the repsitory that are not marked as deleted.")
|
@Description("Counts all software modules in the repsitory that are not marked as deleted.")
|
||||||
public void countSoftwareModulesAll() {
|
void countSoftwareModulesAll() {
|
||||||
// found in test
|
// found in test
|
||||||
testdataFactory.createSoftwareModuleOs("one");
|
testdataFactory.createSoftwareModuleOs("one");
|
||||||
testdataFactory.createSoftwareModuleOs("two");
|
testdataFactory.createSoftwareModuleOs("two");
|
||||||
@@ -256,7 +256,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Deletes an artifact, which is not assigned to a Distribution Set")
|
@Description("Deletes an artifact, which is not assigned to a Distribution Set")
|
||||||
public void hardDeleteOfNotAssignedArtifact() {
|
void hardDeleteOfNotAssignedArtifact() {
|
||||||
|
|
||||||
// [STEP1]: Create SoftwareModuleX with Artifacts
|
// [STEP1]: Create SoftwareModuleX with Artifacts
|
||||||
final SoftwareModule unassignedModule = createSoftwareModuleWithArtifacts(osType, "moduleX", "3.0.2", 2);
|
final SoftwareModule unassignedModule = createSoftwareModuleWithArtifacts(osType, "moduleX", "3.0.2", 2);
|
||||||
@@ -282,8 +282,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Deletes an artifact, which is assigned to a DistributionSet")
|
@Description("Deletes an artifact, which is assigned to a DistributionSet")
|
||||||
public void softDeleteOfAssignedArtifact() {
|
void softDeleteOfAssignedArtifact() {
|
||||||
|
|
||||||
// [STEP1]: Create SoftwareModuleX with ArtifactX
|
// [STEP1]: Create SoftwareModuleX with ArtifactX
|
||||||
SoftwareModule assignedModule = createSoftwareModuleWithArtifacts(osType, "moduleX", "3.0.2", 2);
|
SoftwareModule assignedModule = createSoftwareModuleWithArtifacts(osType, "moduleX", "3.0.2", 2);
|
||||||
|
|
||||||
@@ -315,7 +314,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Delete an artifact, which has been assigned to a rolled out DistributionSet in the past")
|
@Description("Delete an artifact, which has been assigned to a rolled out DistributionSet in the past")
|
||||||
public void softDeleteOfHistoricalAssignedArtifact() {
|
void softDeleteOfHistoricalAssignedArtifact() {
|
||||||
|
|
||||||
// Init target
|
// Init target
|
||||||
final Target target = testdataFactory.createTarget();
|
final Target target = testdataFactory.createTarget();
|
||||||
@@ -355,7 +354,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Delete an software module with an artifact, which is also used by another software module.")
|
@Description("Delete an software module with an artifact, which is also used by another software module.")
|
||||||
public void deleteSoftwareModulesWithSharedArtifact() {
|
void deleteSoftwareModulesWithSharedArtifact() {
|
||||||
|
|
||||||
// Init artifact binary data, target and DistributionSets
|
// Init artifact binary data, target and DistributionSets
|
||||||
final int artifactSize = 1024;
|
final int artifactSize = 1024;
|
||||||
@@ -401,7 +400,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Delete two assigned softwaremodules which share an artifact.")
|
@Description("Delete two assigned softwaremodules which share an artifact.")
|
||||||
public void deleteMultipleSoftwareModulesWhichShareAnArtifact() {
|
void deleteMultipleSoftwareModulesWhichShareAnArtifact() {
|
||||||
// Init artifact binary data, target and DistributionSets
|
// Init artifact binary data, target and DistributionSets
|
||||||
final int artifactSize = 1024;
|
final int artifactSize = 1024;
|
||||||
final byte[] source = RandomUtils.nextBytes(artifactSize);
|
final byte[] source = RandomUtils.nextBytes(artifactSize);
|
||||||
@@ -460,7 +459,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that all undeleted software modules are found in the repository.")
|
@Description("Verifies that all undeleted software modules are found in the repository.")
|
||||||
public void countSoftwareModuleTypesAll() {
|
void countSoftwareModuleTypesAll() {
|
||||||
testdataFactory.createSoftwareModuleOs();
|
testdataFactory.createSoftwareModuleOs();
|
||||||
|
|
||||||
// one soft deleted
|
// one soft deleted
|
||||||
@@ -474,7 +473,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that software modules are returned that are assigned to given DS.")
|
@Description("Verifies that software modules are returned that are assigned to given DS.")
|
||||||
public void findSoftwareModuleByAssignedTo() {
|
void findSoftwareModuleByAssignedTo() {
|
||||||
// test modules
|
// test modules
|
||||||
final SoftwareModule one = testdataFactory.createSoftwareModuleOs();
|
final SoftwareModule one = testdataFactory.createSoftwareModuleOs();
|
||||||
testdataFactory.createSoftwareModuleOs("notassigned");
|
testdataFactory.createSoftwareModuleOs("notassigned");
|
||||||
@@ -491,7 +490,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Checks that metadata for a software module can be created.")
|
@Description("Checks that metadata for a software module can be created.")
|
||||||
public void createSoftwareModuleMetadata() {
|
void createSoftwareModuleMetadata() {
|
||||||
final String knownKey1 = "myKnownKey1";
|
final String knownKey1 = "myKnownKey1";
|
||||||
final String knownValue1 = "myKnownValue1";
|
final String knownValue1 = "myKnownValue1";
|
||||||
|
|
||||||
@@ -523,7 +522,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies the enforcement of the metadata quota per software module.")
|
@Description("Verifies the enforcement of the metadata quota per software module.")
|
||||||
public void createSoftwareModuleMetadataUntilQuotaIsExceeded() {
|
void createSoftwareModuleMetadataUntilQuotaIsExceeded() {
|
||||||
|
|
||||||
// add meta data one by one
|
// add meta data one by one
|
||||||
final SoftwareModule module = testdataFactory.createSoftwareModuleApp("m1");
|
final SoftwareModule module = testdataFactory.createSoftwareModuleApp("m1");
|
||||||
@@ -569,7 +568,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Checks that metadata for a software module cannot be created for an existing key.")
|
@Description("Checks that metadata for a software module cannot be created for an existing key.")
|
||||||
public void createSoftwareModuleMetadataFailsIfKeyExists() {
|
void createSoftwareModuleMetadataFailsIfKeyExists() {
|
||||||
|
|
||||||
final String knownKey1 = "myKnownKey1";
|
final String knownKey1 = "myKnownKey1";
|
||||||
final String knownValue1 = "myKnownValue1";
|
final String knownValue1 = "myKnownValue1";
|
||||||
@@ -597,7 +596,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@WithUser(allSpPermissions = true)
|
@WithUser(allSpPermissions = true)
|
||||||
@Description("Checks that metadata for a software module can be updated.")
|
@Description("Checks that metadata for a software module can be updated.")
|
||||||
public void updateSoftwareModuleMetadata() {
|
void updateSoftwareModuleMetadata() {
|
||||||
final String knownKey = "myKnownKey";
|
final String knownKey = "myKnownKey";
|
||||||
final String knownValue = "myKnownValue";
|
final String knownValue = "myKnownValue";
|
||||||
final String knownUpdateValue = "myNewUpdatedValue";
|
final String knownUpdateValue = "myNewUpdatedValue";
|
||||||
@@ -637,7 +636,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that existing metadata can be deleted.")
|
@Description("Verifies that existing metadata can be deleted.")
|
||||||
public void deleteSoftwareModuleMetadata() {
|
void deleteSoftwareModuleMetadata() {
|
||||||
final String knownKey1 = "myKnownKey1";
|
final String knownKey1 = "myKnownKey1";
|
||||||
final String knownValue1 = "myKnownValue1";
|
final String knownValue1 = "myKnownValue1";
|
||||||
|
|
||||||
@@ -660,7 +659,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that non existing metadata find results in exception.")
|
@Description("Verifies that non existing metadata find results in exception.")
|
||||||
public void findSoftwareModuleMetadataFailsIfEntryDoesNotExist() {
|
void findSoftwareModuleMetadataFailsIfEntryDoesNotExist() {
|
||||||
final String knownKey1 = "myKnownKey1";
|
final String knownKey1 = "myKnownKey1";
|
||||||
final String knownValue1 = "myKnownValue1";
|
final String knownValue1 = "myKnownValue1";
|
||||||
|
|
||||||
@@ -674,7 +673,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Queries and loads the metadata related to a given software module.")
|
@Description("Queries and loads the metadata related to a given software module.")
|
||||||
public void findAllSoftwareModuleMetadataBySwId() {
|
void findAllSoftwareModuleMetadataBySwId() {
|
||||||
|
|
||||||
final SoftwareModule sw1 = testdataFactory.createSoftwareModuleApp();
|
final SoftwareModule sw1 = testdataFactory.createSoftwareModuleApp();
|
||||||
final int metadataCountSw1 = 8;
|
final int metadataCountSw1 = 8;
|
||||||
|
|||||||
Reference in New Issue
Block a user