Feature Approval Workflow for rollouts (#678)
* implement feature approval workflow Signed-off-by: Ioannis Spyropoulos <ioannis.spyropoulos@bosch-si.com> Signed-off-by: Michael Müller <Michael.Mueller17@bosch-si.com> * add documentation for REST endpoints Signed-off-by: Ioannis Spyropoulos <ioannis.spyropoulos@bosch-si.com> Signed-off-by: Michael Müller <Michael.Mueller17@bosch-si.com> * fix broken documentation test Signed-off-by: Ioannis Spyropoulos <ioannis.spyropoulos@bosch-si.com> * fix broken documentation test II Signed-off-by: Ioannis Spyropoulos <ioannis.spyropoulos@bosch-si.com>
This commit is contained in:
committed by
Dominic Schabel
parent
8a14c931c8
commit
cef7c2bbf2
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
|
||||
import org.eclipse.hawkbit.repository.RolloutApprovalStrategy;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link RolloutApprovalStrategy}. Decides whether
|
||||
* approval is needed based on configuration of the tenant as well as the roles
|
||||
* of the user who created the Rollout. Provides a no-operation implementation
|
||||
* of {@link RolloutApprovalStrategy#onApprovalRequired(Rollout)}.
|
||||
*/
|
||||
public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy {
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
DefaultRolloutApprovalStrategy(UserDetailsService userDetailsService,
|
||||
TenantConfigurationManagement tenantConfigurationManagement,
|
||||
SystemSecurityContext systemSecurityContext) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if rollout approval is enabled and rollout creator doesn't have
|
||||
* approval role.
|
||||
*/
|
||||
@Override
|
||||
public boolean isApprovalNeeded(final Rollout rollout) {
|
||||
final UserDetails userDetails = this.getActor(rollout);
|
||||
final boolean approvalEnabled = this.tenantConfigurationManagement
|
||||
.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue();
|
||||
return approvalEnabled && userDetails.getAuthorities().stream()
|
||||
.noneMatch(authority -> SpPermission.APPROVE_ROLLOUT.equals(authority.getAuthority()));
|
||||
}
|
||||
|
||||
|
||||
private UserDetails getActor(Rollout rollout) {
|
||||
final String actor = rollout.getLastModifiedBy() != null ? rollout.getLastModifiedBy() : rollout.getCreatedBy();
|
||||
return systemSecurityContext.runAsSystem(() -> {
|
||||
UserPrincipal userPrincipal = (UserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
if(userPrincipal.getUsername().equals(actor)) {
|
||||
return userPrincipal;
|
||||
} else {
|
||||
return this.userDetailsService.loadUserByUsername(actor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/***
|
||||
* Per default do nothing.
|
||||
*
|
||||
* @param rollout
|
||||
* rollout to create approval task for.
|
||||
*/
|
||||
@Override
|
||||
public void onApprovalRequired(Rollout rollout) {
|
||||
// do nothing per default, can be extended by further implementations.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApprovalUser(Rollout rollout) {
|
||||
return SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.AbstractRolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutApprovalStrategy;
|
||||
import org.eclipse.hawkbit.repository.RolloutFields;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutHelper;
|
||||
@@ -157,9 +158,9 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
final DistributionSetManagement distributionSetManagement, final ApplicationContext context,
|
||||
final ApplicationEventPublisher eventPublisher, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final PlatformTransactionManager txManager, final TenantAware tenantAware, final LockRegistry lockRegistry,
|
||||
final Database database) {
|
||||
final Database database, final RolloutApprovalStrategy rolloutApprovalStrategy) {
|
||||
super(targetManagement, deploymentManagement, rolloutGroupManagement, distributionSetManagement, context,
|
||||
eventPublisher, virtualPropertyReplacer, txManager, tenantAware, lockRegistry);
|
||||
eventPublisher, virtualPropertyReplacer, txManager, tenantAware, lockRegistry, rolloutApprovalStrategy);
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
@@ -357,8 +358,14 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
// When all groups are ready the rollout status can be changed to be
|
||||
// ready, too.
|
||||
if (readyGroups == rolloutGroups.size()) {
|
||||
LOGGER.debug("rollout {} creation done. Switch to READY.", rollout.getId());
|
||||
rollout.setStatus(RolloutStatus.READY);
|
||||
if (!rolloutApprovalStrategy.isApprovalNeeded(rollout)) {
|
||||
rollout.setStatus(RolloutStatus.READY);
|
||||
LOGGER.debug("rollout {} creation done. Switch to READY.", rollout.getId());
|
||||
} else {
|
||||
LOGGER.debug("rollout {} creation done. Switch to WAITING_FOR_APPROVAL.", rollout.getId());
|
||||
rollout.setStatus(RolloutStatus.WAITING_FOR_APPROVAL);
|
||||
rolloutApprovalStrategy.onApprovalRequired(rollout);
|
||||
}
|
||||
rollout.setLastCheck(0);
|
||||
rollout.setTotalTargets(totalTargets);
|
||||
rolloutRepository.save(rollout);
|
||||
@@ -451,6 +458,39 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
groups.stream().map(RolloutGroupCreate::build).collect(Collectors.toList()), baseFilter, totalTargets));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Rollout approveOrDeny(final long rolloutId, final Rollout.ApprovalDecision decision) {
|
||||
return this.approveOrDeny(rolloutId, decision, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Rollout approveOrDeny(final long rolloutId, final Rollout.ApprovalDecision decision, final String remark) {
|
||||
LOGGER.debug("approveOrDeny rollout called for rollout {} with decision {}", rolloutId, decision);
|
||||
final JpaRollout rollout = getRolloutAndThrowExceptionIfNotFound(rolloutId);
|
||||
RolloutHelper.verifyRolloutInStatus(rollout, RolloutStatus.WAITING_FOR_APPROVAL);
|
||||
switch (decision) {
|
||||
case APPROVED:
|
||||
rollout.setStatus(RolloutStatus.READY);
|
||||
break;
|
||||
case DENIED:
|
||||
rollout.setStatus(RolloutStatus.APPROVAL_DENIED);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown approval decision: " + decision);
|
||||
}
|
||||
rollout.setApprovalDecidedBy(rolloutApprovalStrategy.getApprovalUser(rollout));
|
||||
if (remark != null) {
|
||||
rollout.setApprovalRemark(remark);
|
||||
}
|
||||
return rolloutRepository.save(rollout);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
@@ -964,7 +1004,6 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
final JpaRollout rollout = getRolloutAndThrowExceptionIfNotFound(update.getId());
|
||||
|
||||
checkIfDeleted(update.getId(), rollout.getStatus());
|
||||
|
||||
update.getName().ifPresent(rollout::setName);
|
||||
update.getDescription().ifPresent(rollout::setDescription);
|
||||
update.getActionType().ifPresent(rollout::setActionType);
|
||||
@@ -976,6 +1015,11 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
|
||||
rollout.setDistributionSet(set);
|
||||
});
|
||||
if (rolloutApprovalStrategy.isApprovalNeeded(rollout)) {
|
||||
rollout.setStatus(RolloutStatus.WAITING_FOR_APPROVAL);
|
||||
rollout.setApprovalDecidedBy(null);
|
||||
rollout.setApprovalRemark(null);
|
||||
}
|
||||
|
||||
return rolloutRepository.save(rollout);
|
||||
}
|
||||
@@ -1067,7 +1111,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
/**
|
||||
* Enforces the quota defining the maximum number of {@link Target}s per
|
||||
* {@link RolloutGroup}.
|
||||
*
|
||||
*
|
||||
* @param group
|
||||
* The rollout group
|
||||
* @param requested
|
||||
@@ -1081,7 +1125,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
/**
|
||||
* Enforces the quota defining the maximum number of {@link Action}s per
|
||||
* {@link Target}.
|
||||
*
|
||||
*
|
||||
* @param target
|
||||
* The target
|
||||
* @param requested
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.eclipse.hawkbit.repository.PropertiesQuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryDefaultConfiguration;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.RolloutApprovalStrategy;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
@@ -106,6 +107,7 @@ import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
|
||||
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
|
||||
import org.springframework.retry.annotation.EnableRetry;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
@@ -471,7 +473,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
* to access quotas
|
||||
* @param properties
|
||||
* JPA properties
|
||||
*
|
||||
*
|
||||
* @return a new {@link TargetFilterQueryManagement}
|
||||
*/
|
||||
@Bean
|
||||
@@ -559,10 +561,25 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final DistributionSetManagement distributionSetManagement, final ApplicationContext context,
|
||||
final ApplicationEventPublisher eventPublisher, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final PlatformTransactionManager txManager, final TenantAware tenantAware, final LockRegistry lockRegistry,
|
||||
final JpaProperties properties) {
|
||||
final JpaProperties properties, final RolloutApprovalStrategy rolloutApprovalStrategy) {
|
||||
return new JpaRolloutManagement(targetManagement, deploymentManagement, rolloutGroupManagement,
|
||||
distributionSetManagement, context, eventPublisher, virtualPropertyReplacer, txManager, tenantAware,
|
||||
lockRegistry, properties.getDatabase());
|
||||
lockRegistry, properties.getDatabase(), rolloutApprovalStrategy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link DefaultRolloutApprovalStrategy} bean.
|
||||
*
|
||||
* @return a new {@link RolloutApprovalStrategy}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RolloutApprovalStrategy rolloutApprovalStrategy(final UserDetailsService userDetailsService,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
return new DefaultRolloutApprovalStrategy(userDetailsService, tenantConfigurationManagement,
|
||||
systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -88,7 +88,9 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
@ConversionValue(objectValue = "ERROR_CREATING", dataValue = "7"),
|
||||
@ConversionValue(objectValue = "ERROR_STARTING", dataValue = "8"),
|
||||
@ConversionValue(objectValue = "DELETING", dataValue = "9"),
|
||||
@ConversionValue(objectValue = "DELETED", dataValue = "10") })
|
||||
@ConversionValue(objectValue = "DELETED", dataValue = "10"),
|
||||
@ConversionValue(objectValue = "WAITING_FOR_APPROVAL", dataValue = "11"),
|
||||
@ConversionValue(objectValue = "APPROVAL_DENIED", dataValue = "12")})
|
||||
@Convert("rolloutstatus")
|
||||
@NotNull
|
||||
private RolloutStatus status = RolloutStatus.CREATING;
|
||||
@@ -120,6 +122,14 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
@Column(name = "start_at")
|
||||
private Long startAt;
|
||||
|
||||
@Column(name = "approval_decided_by")
|
||||
@Size(min = 1, max = Rollout.APPROVED_BY_MAX_SIZE)
|
||||
private String approvalDecidedBy;
|
||||
|
||||
@Column(name = "approval_remark")
|
||||
@Size(max = Rollout.APPROVAL_REMARK_MAX_SIZE)
|
||||
private String approvalRemark;
|
||||
|
||||
@Transient
|
||||
private transient TotalTargetCountStatus totalTargetCountStatus;
|
||||
|
||||
@@ -271,4 +281,22 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApprovalDecidedBy() {
|
||||
return approvalDecidedBy;
|
||||
}
|
||||
|
||||
public void setApprovalDecidedBy(final String approvalDecidedBy) {
|
||||
this.approvalDecidedBy = approvalDecidedBy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApprovalRemark() {
|
||||
return approvalRemark;
|
||||
}
|
||||
|
||||
public void setApprovalRemark(final String approvalRemark) {
|
||||
this.approvalRemark = approvalRemark;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE sp_rollout ADD column approval_decided_by varchar(40);
|
||||
ALTER TABLE sp_rollout ADD column approval_remark varchar(255);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE sp_rollout ADD column approval_decided_by varchar(40);
|
||||
ALTER TABLE sp_rollout ADD column approval_remark varchar(255);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE sp_rollout ADD column approval_decided_by varchar(40);
|
||||
ALTER TABLE sp_rollout ADD column approval_remark varchar(255);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE sp_rollout ADD column approval_decided_by varchar(40);
|
||||
ALTER TABLE sp_rollout ADD column approval_remark varchar(255);
|
||||
@@ -27,6 +27,7 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.test.util.RolloutTestApprovalStrategy;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
@@ -95,6 +96,9 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
@Autowired
|
||||
protected TenantConfigurationProperties tenantConfigurationProperties;
|
||||
|
||||
@Autowired
|
||||
protected RolloutTestApprovalStrategy approvalStrategy;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
protected List<Action> findActionsByRolloutAndStatus(final Rollout rollout, final Action.Status actionStatus) {
|
||||
return Lists.newArrayList(actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), actionStatus));
|
||||
|
||||
@@ -68,12 +68,17 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Step;
|
||||
@@ -87,6 +92,12 @@ import ru.yandex.qatools.allure.annotations.Title;
|
||||
@Stories("Rollout Management")
|
||||
public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Before
|
||||
@After
|
||||
public void reset() {
|
||||
this.approvalStrategy.setApprovalNeeded(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that a running action with distribution-set (A) is not canceled by a rollout which tries to also assign a distribution-set (A)")
|
||||
public void rolloutShouldNotCancelRunningActionWithTheSameDistributionSet() {
|
||||
@@ -1539,6 +1550,59 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Creating a rollout with approval role or approval engine disabled results in the rollout being in " +
|
||||
"READY state.")
|
||||
public void createdRolloutWithApprovalRoleOrApprovalDisabledTransitionsToReadyState() {
|
||||
approvalStrategy.setApprovalNeeded(false);
|
||||
final String successCondition = "50";
|
||||
final String errorCondition = "80";
|
||||
final Rollout rollout = createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10,
|
||||
5, successCondition, errorCondition);
|
||||
assertThat(rollout.getStatus()).isEqualTo(Rollout.RolloutStatus.READY);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Creating a rollout without approver role and approval enabled leads to transition to " +
|
||||
"WAITING_FOR_APPROVAL state.")
|
||||
public void createdRolloutWithoutApprovalRoleTransitionsToWaitingForApprovalState() {
|
||||
approvalStrategy.setApprovalNeeded(true);
|
||||
final String successCondition = "50";
|
||||
final String errorCondition = "80";
|
||||
final Rollout rollout = createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10,
|
||||
5, successCondition, errorCondition);
|
||||
assertThat(rollout.getStatus()).isEqualTo(Rollout.RolloutStatus.WAITING_FOR_APPROVAL);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Description("Approving a rollout leads to transition to READY state.")
|
||||
public void approvedRolloutTransitionsToReadyState() {
|
||||
approvalStrategy.setApprovalNeeded(true);
|
||||
final String successCondition = "50";
|
||||
final String errorCondition = "80";
|
||||
final Rollout rollout = createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10,
|
||||
5, successCondition, errorCondition);
|
||||
assertThat(rollout.getStatus()).isEqualTo(Rollout.RolloutStatus.WAITING_FOR_APPROVAL);
|
||||
rolloutManagement.approveOrDeny(rollout.getId(), Rollout.ApprovalDecision.APPROVED);
|
||||
final Rollout resultingRollout = rolloutRepository.findOne(rollout.getId());
|
||||
assertThat(resultingRollout.getStatus()).isEqualTo(Rollout.RolloutStatus.READY);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Denying approval for a rollout leads to transition to APPROVAL_DENIED state.")
|
||||
public void deniedRolloutTransitionsToApprovalDeniedState() {
|
||||
approvalStrategy.setApprovalNeeded(true);
|
||||
final String successCondition = "50";
|
||||
final String errorCondition = "80";
|
||||
final Rollout rollout = createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10,
|
||||
5, successCondition, errorCondition);
|
||||
assertThat(rollout.getStatus()).isEqualTo(Rollout.RolloutStatus.WAITING_FOR_APPROVAL);
|
||||
rolloutManagement.approveOrDeny(rollout.getId(), Rollout.ApprovalDecision.DENIED);
|
||||
final Rollout resultingRollout = rolloutRepository.findOne(rollout.getId());
|
||||
assertThat(resultingRollout.getStatus()).isEqualTo(RolloutStatus.APPROVAL_DENIED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExpectEvents({ @Expect(type = RolloutDeletedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
|
||||
Reference in New Issue
Block a user