Feature action cleanup (#704)

* Initial commit
* Tenant configuration enhancements
* Update REST documentation
* Enhance System Configuration view in UI
* Add unit tests
* Fix delete query for H2
* Improve test coverage
* Fix Sonar findings
* Fix Hawkbit bot findings
* Fix PR review findings
* Fix peer review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>
This commit is contained in:
Stefan Behl
2018-07-19 15:23:14 +02:00
committed by GitHub
parent 5e9b0fb884
commit 19caff6e46
28 changed files with 1165 additions and 83 deletions

View File

@@ -0,0 +1,227 @@
/**
* 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.autocleanup;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_ACTION_EXPIRY;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_ACTION_STATUS;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_ENABLED;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test class for {@link AutoActionCleanup}.
*
*/
@Features("Component Tests - Repository")
@Stories("Action cleanup handler")
public class AutoActionCleanupTest extends AbstractJpaIntegrationTest {
@Autowired
private AutoActionCleanup autoActionCleanup;
@Test
@Description("Verifies that running actions are not cleaned up.")
public void runningActionsAreNotCleanedUp() {
// cleanup config for this test case
setupCleanupConfiguration(true, 0, Action.Status.CANCELED, Action.Status.ERROR);
final Target trg1 = testdataFactory.createTarget("trg1");
final Target trg2 = testdataFactory.createTarget("trg2");
final DistributionSet ds1 = testdataFactory.createDistributionSet("ds1");
final DistributionSet ds2 = testdataFactory.createDistributionSet("ds2");
deploymentManagement.assignDistributionSet(ds1.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg1.getControllerId()));
deploymentManagement.assignDistributionSet(ds2.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg2.getControllerId()));
assertThat(actionRepository.count()).isEqualTo(2);
autoActionCleanup.run();
assertThat(actionRepository.count()).isEqualTo(2);
}
@Test
@Description("Verifies that nothing is cleaned up if the cleanup is disabled.")
public void cleanupDisabled() {
// cleanup config for this test case
setupCleanupConfiguration(false, 0, Action.Status.CANCELED);
final Target trg1 = testdataFactory.createTarget("trg1");
final Target trg2 = testdataFactory.createTarget("trg2");
final DistributionSet ds1 = testdataFactory.createDistributionSet("ds1");
final DistributionSet ds2 = testdataFactory.createDistributionSet("ds2");
final Long action1 = deploymentManagement.assignDistributionSet(ds1.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg1.getControllerId())).getActions().get(0);
deploymentManagement.assignDistributionSet(ds2.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg2.getControllerId()));
setActionToCanceled(action1);
assertThat(actionRepository.count()).isEqualTo(2);
autoActionCleanup.run();
assertThat(actionRepository.count()).isEqualTo(2);
}
@Test
@Description("Verifies that canceled and failed actions are cleaned up.")
public void canceledAndFailedActionsAreCleanedUp() {
// cleanup config for this test case
setupCleanupConfiguration(true, 0, Action.Status.CANCELED, Action.Status.ERROR);
final Target trg1 = testdataFactory.createTarget("trg1");
final Target trg2 = testdataFactory.createTarget("trg2");
final Target trg3 = testdataFactory.createTarget("trg3");
final DistributionSet ds1 = testdataFactory.createDistributionSet("ds1");
final DistributionSet ds2 = testdataFactory.createDistributionSet("ds2");
final Long action1 = deploymentManagement.assignDistributionSet(ds1.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg1.getControllerId())).getActions().get(0);
final Long action2 = deploymentManagement.assignDistributionSet(ds2.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg2.getControllerId())).getActions().get(0);
final Long action3 = deploymentManagement.assignDistributionSet(ds2.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg3.getControllerId())).getActions().get(0);
assertThat(actionRepository.count()).isEqualTo(3);
setActionToCanceled(action1);
setActionToFailed(action2);
assertThat(actionRepository.count()).isEqualTo(3);
autoActionCleanup.run();
assertThat(actionRepository.count()).isEqualTo(1);
assertThat(actionRepository.getById(action3)).isPresent();
}
@Test
@Description("Verifies that canceled actions are cleaned up.")
public void canceledActionsAreCleanedUp() {
// cleanup config for this test case
setupCleanupConfiguration(true, 0, Action.Status.CANCELED);
final Target trg1 = testdataFactory.createTarget("trg1");
final Target trg2 = testdataFactory.createTarget("trg2");
final Target trg3 = testdataFactory.createTarget("trg3");
final DistributionSet ds1 = testdataFactory.createDistributionSet("ds1");
final DistributionSet ds2 = testdataFactory.createDistributionSet("ds2");
final Long action1 = deploymentManagement.assignDistributionSet(ds1.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg1.getControllerId())).getActions().get(0);
final Long action2 = deploymentManagement.assignDistributionSet(ds2.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg2.getControllerId())).getActions().get(0);
final Long action3 = deploymentManagement.assignDistributionSet(ds2.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg3.getControllerId())).getActions().get(0);
assertThat(actionRepository.count()).isEqualTo(3);
setActionToCanceled(action1);
setActionToFailed(action2);
assertThat(actionRepository.count()).isEqualTo(3);
autoActionCleanup.run();
assertThat(actionRepository.count()).isEqualTo(2);
assertThat(actionRepository.getById(action2)).isPresent();
assertThat(actionRepository.getById(action3)).isPresent();
}
@Test
@Description("Verifies that canceled and failed actions are cleaned up once they expired.")
@SuppressWarnings("squid:S2925")
public void canceledAndFailedActionsAreCleanedUpWhenExpired() throws InterruptedException {
// cleanup config for this test case
setupCleanupConfiguration(true, 500, Action.Status.CANCELED, Action.Status.ERROR);
final Target trg1 = testdataFactory.createTarget("trg1");
final Target trg2 = testdataFactory.createTarget("trg2");
final Target trg3 = testdataFactory.createTarget("trg3");
final DistributionSet ds1 = testdataFactory.createDistributionSet("ds1");
final DistributionSet ds2 = testdataFactory.createDistributionSet("ds2");
final Long action1 = deploymentManagement.assignDistributionSet(ds1.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg1.getControllerId())).getActions().get(0);
final Long action2 = deploymentManagement.assignDistributionSet(ds2.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg2.getControllerId())).getActions().get(0);
final Long action3 = deploymentManagement.assignDistributionSet(ds2.getId(), ActionType.FORCED, 0,
Collections.singletonList(trg3.getControllerId())).getActions().get(0);
assertThat(actionRepository.count()).isEqualTo(3);
setActionToCanceled(action1);
setActionToFailed(action2);
autoActionCleanup.run();
// actions have not expired yet
assertThat(actionRepository.count()).isEqualTo(3);
// wait for expiry to elapse
Thread.sleep(800);
autoActionCleanup.run();
assertThat(actionRepository.count()).isEqualTo(1);
assertThat(actionRepository.getById(action3)).isPresent();
}
private void setActionToCanceled(final Long id) {
deploymentManagement.cancelAction(id);
deploymentManagement.forceQuitAction(id);
}
private void setActionToFailed(final Long id) {
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(id).status(Status.ERROR));
}
private void setupCleanupConfiguration(final boolean cleanupEnabled, final long expiry, final Status... status) {
tenantConfigurationManagement.addOrUpdateConfiguration(ACTION_CLEANUP_ENABLED, cleanupEnabled);
tenantConfigurationManagement.addOrUpdateConfiguration(ACTION_CLEANUP_ACTION_EXPIRY, expiry);
tenantConfigurationManagement.addOrUpdateConfiguration(ACTION_CLEANUP_ACTION_STATUS,
Arrays.stream(status).map(Status::toString).collect(Collectors.joining(",")));
}
}

View File

@@ -0,0 +1,84 @@
/**
* 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.autocleanup;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.support.locks.LockRegistry;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test class for {@link AutoCleanupScheduler}.
*
*/
@Features("Component Tests - Repository")
@Stories("Auto cleanup scheduler")
public class AutoCleanupSchedulerTest extends AbstractJpaIntegrationTest {
private final AtomicInteger counter = new AtomicInteger();
@Autowired
private LockRegistry lockRegistry;
@Before
public void setUp() {
counter.set(0);
}
@Test
@Description("Verifies that all cleanup handlers are executed regardless if one of them throws an error")
public void executeHandlerChain() {
new AutoCleanupScheduler(systemManagement, systemSecurityContext, lockRegistry, Arrays.asList(
new SuccessfulCleanup(), new SuccessfulCleanup(), new FailingCleanup(), new SuccessfulCleanup())).run();
assertThat(counter.get()).isEqualTo(4);
}
private class SuccessfulCleanup implements CleanupTask {
@Override
public void run() {
counter.incrementAndGet();
}
@Override
public String getId() {
return "success";
}
}
private class FailingCleanup implements CleanupTask {
@Override
public void run() {
counter.incrementAndGet();
throw new RuntimeException("cleanup failed");
}
@Override
public String getId() {
return "success";
}
}
}