Code format hawkbit-repository-jpa (#1928)

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-11-05 09:54:34 +02:00
committed by GitHub
parent da7fa9e022
commit ef857baa9e
371 changed files with 12299 additions and 12525 deletions

View File

@@ -14,6 +14,8 @@ import static org.junit.jupiter.api.Assertions.fail;
import java.util.LinkedHashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.hawkbit.event.BusProtoStuffMessageConverter;
import org.eclipse.hawkbit.repository.event.TenantAwareEvent;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -32,9 +34,6 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Test the remote entity events.
*/
@@ -56,6 +55,23 @@ public abstract class AbstractRemoteEventTest extends AbstractJpaIntegrationTest
}
protected Message<?> createMessageWithImmutableHeader(final TenantAwareEvent event) {
final Map<String, Object> headers = new LinkedHashMap<>();
return busProtoStuffMessageConverter.toMessage(event, new MessageHeaders(headers));
}
@SuppressWarnings("unchecked")
protected <T extends TenantAwareEvent> T createJacksonEvent(final T event) {
final Message<String> message = createJsonMessage(event);
return (T) jacksonMessageConverter.fromMessage(message, event.getClass());
}
@SuppressWarnings("unchecked")
protected <T extends TenantAwareEvent> T createProtoStuffEvent(final T event) {
final Message<?> message = createProtoStuffMessage(event);
return (T) busProtoStuffMessageConverter.fromMessage(message, event.getClass());
}
private Message<?> createProtoStuffMessage(final TenantAwareEvent event) {
final Map<String, Object> headers = new LinkedHashMap<>();
headers.put(MessageHeaders.CONTENT_TYPE, BusProtoStuffMessageConverter.APPLICATION_BINARY_PROTOSTUFF);
@@ -74,21 +90,4 @@ public abstract class AbstractRemoteEventTest extends AbstractJpaIntegrationTest
}
return null;
}
protected Message<?> createMessageWithImmutableHeader(final TenantAwareEvent event) {
final Map<String, Object> headers = new LinkedHashMap<>();
return busProtoStuffMessageConverter.toMessage(event, new MessageHeaders(headers));
}
@SuppressWarnings("unchecked")
protected <T extends TenantAwareEvent> T createJacksonEvent(final T event) {
final Message<String> message = createJsonMessage(event);
return (T) jacksonMessageConverter.fromMessage(message, event.getClass());
}
@SuppressWarnings("unchecked")
protected <T extends TenantAwareEvent> T createProtoStuffEvent(final T event) {
final Message<?> message = createProtoStuffMessage(event);
return (T) busProtoStuffMessageConverter.fromMessage(message, event.getClass());
}
}

View File

@@ -18,10 +18,8 @@ import java.util.Arrays;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**

View File

@@ -15,6 +15,9 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -23,10 +26,6 @@ import org.eclipse.hawkbit.repository.model.ActionProperties;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RemoteTenantAwareEvent Tests")
public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
@@ -53,16 +52,6 @@ public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
assertThat(remoteAssignEventJackson.getControllerIds()).containsExactlyElementsOf(controllerIds);
}
private Action createAction(final String controllerId) {
long id = 1;
final JpaAction generateAction = new JpaAction();
generateAction.setId(id++);
generateAction.setActionType(ActionType.FORCED);
generateAction.setTarget(testdataFactory.createTarget(controllerId));
generateAction.setStatus(Status.RUNNING);
return generateAction;
}
@Test
@Description("Verifies that a MultiActionCancelEvent can be properly serialized and deserialized")
public void testMultiActionCancelEvent() {
@@ -148,6 +137,16 @@ public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
assertCancelTargetAssignmentEvent(action, remoteEventJackson);
}
private Action createAction(final String controllerId) {
long id = 1;
final JpaAction generateAction = new JpaAction();
generateAction.setId(id++);
generateAction.setActionType(ActionType.FORCED);
generateAction.setTarget(testdataFactory.createTarget(controllerId));
generateAction.setStatus(Status.RUNNING);
return generateAction;
}
private void assertTargetAssignDistributionSetEvent(final Action action,
final TargetAssignDistributionSetEvent underTest) {

View File

@@ -15,10 +15,9 @@ import static org.junit.jupiter.api.Assertions.fail;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEventTest;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEventTest;
/**
* Test the remote entity events.

View File

@@ -11,7 +11,9 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
import static org.assertj.core.api.Assertions.assertThat;
import net.bytebuddy.agent.builder.AgentBuilder;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -20,10 +22,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test the remote entity events.
*/

View File

@@ -9,11 +9,10 @@
*/
package org.eclipse.hawkbit.repository.event.remote.entity;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.junit.jupiter.api.Test;
/**

View File

@@ -9,12 +9,11 @@
*/
package org.eclipse.hawkbit.repository.event.remote.entity;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.junit.jupiter.api.Test;
/**
* Test the remote entity events.

View File

@@ -9,12 +9,11 @@
*/
package org.eclipse.hawkbit.repository.event.remote.entity;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.junit.jupiter.api.Test;
/**
* Test the remote entity events.

View File

@@ -11,6 +11,9 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
import java.util.Collections;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
@@ -18,10 +21,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test the remote entity events.
*/

View File

@@ -14,6 +14,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.util.Collections;
import java.util.UUID;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
@@ -22,10 +25,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test the remote entity events.
*/

View File

@@ -9,12 +9,11 @@
*/
package org.eclipse.hawkbit.repository.event.remote.entity;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.junit.jupiter.api.Test;
/**
* Test the remote entity events.

View File

@@ -9,14 +9,11 @@
*/
package org.eclipse.hawkbit.repository.event.remote.entity;
import static org.assertj.core.api.Assertions.assertThat;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.jupiter.api.Test;
/**
* Test the remote entity events.

View File

@@ -9,12 +9,11 @@
*/
package org.eclipse.hawkbit.repository.event.remote.entity;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.junit.jupiter.api.Test;
/**
* Test the remote entity events.

View File

@@ -9,6 +9,8 @@
*/
package org.eclipse.hawkbit.repository.jpa;
import static org.assertj.core.api.Assertions.assertThat;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.List;
@@ -46,13 +48,11 @@ import org.eclipse.hawkbit.repository.jpa.repository.TenantMetaDataRepository;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
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.model.TargetType;
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
import org.eclipse.hawkbit.repository.test.TestConfiguration;
@@ -69,8 +69,6 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;
import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration(classes = {
RepositoryApplicationConfiguration.class, TestConfiguration.class })
@Import(TestChannelBinderConfiguration.class)
@@ -141,6 +139,34 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
@Autowired
private JpaProperties jpaProperties;
protected static void verifyThrownExceptionBy(final ThrowingCallable tc, final String objectType) {
Assertions.assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(tc)
.withMessageContaining(NOT_EXIST_ID).withMessageContaining(objectType);
}
protected static <T> List<T> toList(final Iterable<? extends T> it) {
return StreamSupport.stream(it.spliterator(), false).map(e -> (T) e).toList();
}
protected static <T> T[] toArray(final Iterable<? extends T> it, final Class<T> type) {
final List<T> list = toList(it);
final T[] array = (T[]) Array.newInstance(type, list.size());
for (int i = 0; i < array.length; i++) {
array[i] = list.get(i);
}
return array;
}
// just increase the opt lock revision if the instance in order to match it against locked db instance - not really locking
protected static void implicitLock(final DistributionSet set) {
((JpaDistributionSet) set).setOptLockRevision(set.getOptLockRevision() + 1);
}
// just increase the opt lock revision if the instance in order to match it against locked db instance - not really locking
protected static void implicitLock(final SoftwareModule module) {
((JpaSoftwareModule) module).setOptLockRevision(module.getOptLockRevision() + 1);
}
protected Database getDatabase() {
return jpaProperties.getDatabase();
}
@@ -150,15 +176,11 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
return toList(actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), actionStatus));
}
protected static void verifyThrownExceptionBy(final ThrowingCallable tc, final String objectType) {
Assertions.assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(tc)
.withMessageContaining(NOT_EXIST_ID).withMessageContaining(objectType);
}
protected List<Target> assignTag(final Collection<Target> targets, final TargetTag tag) {
return targetManagement.assignTag(
targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
}
protected List<Target> unassignTag(final Collection<Target> targets, final TargetTag tag) {
return targetManagement.unassignTag(
targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
@@ -169,6 +191,7 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
return distributionSetManagement.assignTag(
sets.stream().map(DistributionSet::getId).collect(Collectors.toList()), tag.getId());
}
protected List<DistributionSet> unassignTag(final Collection<DistributionSet> sets,
final DistributionSetTag tag) {
return distributionSetManagement.unassignTag(
@@ -180,7 +203,8 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
targets.stream().map(Target::getControllerId).collect(Collectors.toList()), type.getId());
}
protected void assertRollout(final Rollout rollout, final boolean dynamic, final Rollout.RolloutStatus status, final int groupCreated, final long totalTargets) {
protected void assertRollout(final Rollout rollout, final boolean dynamic, final Rollout.RolloutStatus status, final int groupCreated,
final long totalTargets) {
final Rollout refreshed = refresh(rollout);
assertThat(refreshed.isDynamic()).as("Is dynamic").isEqualTo(dynamic);
assertThat(refreshed.getStatus()).as("Status").isEqualTo(status);
@@ -188,7 +212,8 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
assertThat(refreshed.getTotalTargets()).as("Total targets").isEqualTo(totalTargets);
}
protected void assertGroup(final RolloutGroup group, final boolean dynamic, final RolloutGroup.RolloutGroupStatus status, final long totalTargets) {
protected void assertGroup(final RolloutGroup group, final boolean dynamic, final RolloutGroup.RolloutGroupStatus status,
final long totalTargets) {
final RolloutGroup refreshed = refresh(group);
assertThat(refreshed.isDynamic()).as("Is dynamic").isEqualTo(dynamic);
assertThat(refreshed.getStatus()).as("Status").isEqualTo(status);
@@ -215,34 +240,11 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
return targetManagement.getTagsByControllerId(controllerId);
}
private JpaRollout refresh(final Rollout rollout) {
return rolloutRepository.findById(rollout.getId()).get();
}
protected JpaRolloutGroup refresh(final RolloutGroup group) {
return rolloutGroupRepository.findById(group.getId()).get();
}
protected static <T> List<T> toList(final Iterable<? extends T> it) {
return StreamSupport.stream(it.spliterator(), false).map(e -> (T)e).toList();
}
protected static <T> T[] toArray(final Iterable<? extends T> it, final Class<T> type) {
final List<T> list = toList(it);
final T[] array = (T[])Array.newInstance(type, list.size());
for (int i = 0; i < array.length; i++) {
array[i] = list.get(i);
}
return array;
}
// just increase the opt lock revision if the instance in order to match it against locked db instance - not really locking
protected static void implicitLock(final DistributionSet set) {
((JpaDistributionSet) set).setOptLockRevision(set.getOptLockRevision() + 1);
}
// just increase the opt lock revision if the instance in order to match it against locked db instance - not really locking
protected static void implicitLock(final SoftwareModule module) {
((JpaSoftwareModule) module).setOptLockRevision(module.getOptLockRevision() + 1);
private JpaRollout refresh(final Rollout rollout) {
return rolloutRepository.findById(rollout.getId()).get();
}
}

View File

@@ -19,6 +19,9 @@ import java.time.Duration;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.awaitility.Awaitility;
import org.eclipse.hawkbit.repository.exception.StopRolloutException;
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
@@ -40,21 +43,59 @@ import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test class testing the invalidation of a {@link DistributionSet} while the
* handle rollouts is ongoing.
*
*/
@Feature("Component Tests - Repository")
@Story("Concurrent Distribution Set invalidation")
@ContextConfiguration(classes = ConcurrentDistributionSetInvalidationTest.Config.class)
@TestPropertySource(properties = { "hawkbit.server.repository.dsInvalidationLockTimeout=1" })
public class ConcurrentDistributionSetInvalidationTest extends AbstractJpaIntegrationTest {
@Test
@Description("Verify that a large rollout causes a timeout when trying to invalidate a distribution set")
public void verifyInvalidateDistributionSetWithLargeRolloutThrowsException() throws Exception {
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
final Rollout rollout = createRollout(distributionSet);
final String tenant = tenantAware.getCurrentTenant();
// run in new Thread so that the invalidation can be executed in
// parallel
new Thread(() -> systemSecurityContext.runAsSystemAsTenant(() -> {
rolloutHandler.handleAll();
return 0;
}, tenant)).start();
// wait until at least one RolloutGroup is created, as this means that
// the thread has started and has acquired the lock
Awaitility.await().atMost(Duration.ofSeconds(5))
.pollInterval(Duration.ofMillis(100))
.until(() -> tenantAware.runAsTenant(tenant, () -> systemSecurityContext
.runAsSystem(() -> rolloutGroupManagement.findByRollout(PAGE, rollout.getId()).getSize() > 0)));
assertThatExceptionOfType(StopRolloutException.class)
.as("Invalidation of distributionSet should throw an exception")
.isThrownBy(() -> distributionSetInvalidationManagement.invalidateDistributionSet(
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
CancelationType.SOFT, true)));
}
private Rollout createRollout(final DistributionSet distributionSet) {
testdataFactory.createTargets(
quotaManagement.getMaxTargetsPerRolloutGroup() * quotaManagement.getMaxRolloutGroupsPerRollout(),
"verifyInvalidateDistributionSetWithLargeRolloutThrowsException");
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "50")
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, "80")
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
return rolloutManagement.create(entityFactory.rollout().create()
.name("verifyInvalidateDistributionSetWithLargeRolloutThrowsException").description("desc")
.targetFilterQuery("name==*").distributionSetId(distributionSet).actionType(ActionType.FORCED),
quotaManagement.getMaxRolloutGroupsPerRollout(), false, conditions);
}
@Configuration
static class Config {
@@ -80,47 +121,4 @@ public class ConcurrentDistributionSetInvalidationTest extends AbstractJpaIntegr
}
}
@Test
@Description("Verify that a large rollout causes a timeout when trying to invalidate a distribution set")
public void verifyInvalidateDistributionSetWithLargeRolloutThrowsException() throws Exception {
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
final Rollout rollout = createRollout(distributionSet);
final String tenant = tenantAware.getCurrentTenant();
// run in new Thread so that the invalidation can be executed in
// parallel
new Thread(() -> systemSecurityContext.runAsSystemAsTenant(() -> {
rolloutHandler.handleAll();
return 0;
}, tenant)).start();
// wait until at least one RolloutGroup is created, as this means that
// the thread has started and has acquired the lock
Awaitility.await().atMost(Duration.ofSeconds(5))
.pollInterval(Duration.ofMillis(100))
.until(() -> tenantAware.runAsTenant(tenant, () -> systemSecurityContext
.runAsSystem(() -> rolloutGroupManagement.findByRollout(PAGE, rollout.getId()).getSize() > 0)));
assertThatExceptionOfType(StopRolloutException.class)
.as("Invalidation of distributionSet should throw an exception")
.isThrownBy(() -> distributionSetInvalidationManagement.invalidateDistributionSet(
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
CancelationType.SOFT, true)));
}
private Rollout createRollout(final DistributionSet distributionSet) {
testdataFactory.createTargets(
quotaManagement.getMaxTargetsPerRolloutGroup() * quotaManagement.getMaxRolloutGroupsPerRollout(),
"verifyInvalidateDistributionSetWithLargeRolloutThrowsException");
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "50")
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, "80")
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
return rolloutManagement.create(entityFactory.rollout().create()
.name("verifyInvalidateDistributionSetWithLargeRolloutThrowsException").description("desc")
.targetFilterQuery("name==*").distributionSetId(distributionSet).actionType(ActionType.FORCED),
quotaManagement.getMaxRolloutGroupsPerRollout(), false, conditions);
}
}

View File

@@ -18,21 +18,20 @@ import java.sql.SQLException;
import jakarta.persistence.OptimisticLockException;
import jakarta.persistence.PersistenceException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.junit.jupiter.api.Test;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.dao.UncategorizedDataAccessException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Mapping tests for {@link HawkBitEclipseLinkJpaDialect}.
*
*/
@Feature("Unit Tests - Repository")
@Story("Exception handling")
public class HawkBitEclipseLinkJpaDialectTest {
private final HawkBitEclipseLinkJpaDialect hawkBitEclipseLinkJpaDialectUnderTest = new HawkBitEclipseLinkJpaDialect();
@Test
@@ -40,7 +39,7 @@ public class HawkBitEclipseLinkJpaDialectTest {
public void jpaOptimisticLockExceptionIsConcurrencyFailureException() {
assertThat(
hawkBitEclipseLinkJpaDialectUnderTest.translateExceptionIfPossible(mock(OptimisticLockException.class)))
.isInstanceOf(ConcurrencyFailureException.class);
.isInstanceOf(ConcurrencyFailureException.class);
}
@Test

View File

@@ -15,8 +15,6 @@ import java.security.SecureRandom;
import java.util.Random;
/**
*
*
*
*/
public class RandomGeneratedInputStream extends InputStream {
@@ -30,8 +28,7 @@ public class RandomGeneratedInputStream extends InputStream {
private long index;
/**
* @param size
* target size of the stream [byte]
* @param size target size of the stream [byte]
*/
public RandomGeneratedInputStream(final long size) {
this.size = size;

View File

@@ -15,6 +15,9 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.ContextAware;
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -26,10 +29,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

View File

@@ -38,14 +38,10 @@ public abstract class AbstractAccessControllerTest extends AbstractJpaIntegratio
@Autowired
protected TestAccessControlManger testAccessControlManger;
@BeforeEach
void beforeEach() {
testAccessControlManger.deleteAllRules();
}
@AfterEach
void afterEach() {
testAccessControlManger.deleteAllRules();
protected static <T> List<T> merge(final List<T> lists0, final List<T> list1) {
final List<T> merge = new ArrayList<>(lists0);
merge.addAll(list1);
return merge;
}
protected void permitAllOperations(final AccessController.Operation operation) {
@@ -57,6 +53,16 @@ public abstract class AbstractAccessControllerTest extends AbstractJpaIntegratio
JpaDistributionSet.class, operation, Specification.where(null), type -> true);
}
@BeforeEach
void beforeEach() {
testAccessControlManger.deleteAllRules();
}
@AfterEach
void afterEach() {
testAccessControlManger.deleteAllRules();
}
public static class AccessControlTestConfig {
private final ContextAware contextAware = new SecurityContextTenantAware((tenant, username) -> List.of());
@@ -77,7 +83,8 @@ public abstract class AbstractAccessControllerTest extends AbstractJpaIntegratio
@Override
public Optional<Specification<JpaTarget>> getAccessRules(final Operation operation) {
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(contextAware.getCurrentUsername())) {
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(
contextAware.getCurrentUsername())) {
// as tenant, no restrictions
return Optional.empty();
}
@@ -104,7 +111,8 @@ public abstract class AbstractAccessControllerTest extends AbstractJpaIntegratio
@Override
public Optional<Specification<JpaTargetType>> getAccessRules(final Operation operation) {
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(contextAware.getCurrentUsername())) {
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(
contextAware.getCurrentUsername())) {
// as tenant, no restrictions
return Optional.empty();
}
@@ -131,7 +139,8 @@ public abstract class AbstractAccessControllerTest extends AbstractJpaIntegratio
@Override
public Optional<Specification<JpaDistributionSet>> getAccessRules(final Operation operation) {
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(contextAware.getCurrentUsername())) {
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(
contextAware.getCurrentUsername())) {
// as tenant, no restrictions
return Optional.empty();
}
@@ -151,10 +160,4 @@ public abstract class AbstractAccessControllerTest extends AbstractJpaIntegratio
};
}
}
protected static <T> List<T> merge(final List<T> lists0, final List<T> list1) {
final List<T> merge = new ArrayList<>(lists0);
merge.addAll(list1);
return merge;
}
}

View File

@@ -139,8 +139,8 @@ class DistributionSetAccessControllerTest extends AbstractAccessControllerTest {
// verify distributionSetManagement#assignSoftwareModules
assertThat(distributionSetManagement.assignSoftwareModules(permitted.getId(),
Collections.singletonList(swModule.getId()))).satisfies(ds -> {
assertThat(ds.getModules().stream().map(Identifiable::getId).toList()).contains(swModule.getId());
});
assertThat(ds.getModules().stream().map(Identifiable::getId).toList()).contains(swModule.getId());
});
assertThatThrownBy(() -> {
distributionSetManagement.assignSoftwareModules(readOnly.getId(),
Collections.singletonList(swModule.getId()));
@@ -226,8 +226,8 @@ class DistributionSetAccessControllerTest extends AbstractAccessControllerTest {
// assignment is denied for readOnlyTarget (read, but no update permissions)
assertThatThrownBy(() ->
distributionSetManagement.unassignTag(Collections.singletonList(readOnly.getId()), dsTag.getId()))
.as("Missing update permissions for target to toggle tag assignment.")
distributionSetManagement.unassignTag(Collections.singletonList(readOnly.getId()), dsTag.getId()))
.as("Missing update permissions for target to toggle tag assignment.")
.isInstanceOf(InsufficientPermissionException.class);
// assignment is denied for readOnlyTarget (read, but no update permissions)
@@ -296,7 +296,6 @@ class DistributionSetAccessControllerTest extends AbstractAccessControllerTest {
}).isInstanceOf(EntityNotFoundException.class);
}
private void defineAccess(final AccessController.Operation operation, final DistributionSet... distributionSets) {
defineAccess(operation, List.of(distributionSets));
}

View File

@@ -16,6 +16,9 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.FilterParams;
import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
@@ -38,10 +41,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Access Control")
@Story("Test Target Access Controller")
class TargetAccessControllerTest extends AbstractAccessControllerTest {
@@ -328,11 +327,11 @@ class TargetAccessControllerTest extends AbstractAccessControllerTest {
assertThat(content).hasSize(updateTargets.size());
final List<Target> rolloutTargets = content.stream().flatMap(
group -> rolloutGroupManagement.findTargetsOfRolloutGroup(Pageable.unpaged(), group.getId()).get())
group -> rolloutGroupManagement.findTargetsOfRolloutGroup(Pageable.unpaged(), group.getId()).get())
.toList();
assertThat(rolloutTargets).hasSize(updateTargets.size()).allMatch(
target -> updateTargets.stream().anyMatch(readTarget -> readTarget.getId().equals(target.getId())))
target -> updateTargets.stream().anyMatch(readTarget -> readTarget.getId().equals(target.getId())))
.noneMatch(target -> readTargets.stream()
.anyMatch(readTarget -> readTarget.getId().equals(target.getId())))
.noneMatch(target -> hiddenTargets.stream()
@@ -358,7 +357,8 @@ class TargetAccessControllerTest extends AbstractAccessControllerTest {
"hidden5");
defineAccess(AccessController.Operation.UPDATE, updateTargets);
defineAccess(AccessController.Operation.READ, merge(updateTargets, readTargets));;
defineAccess(AccessController.Operation.READ, merge(updateTargets, readTargets));
;
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name("testName").query("id==*"));

View File

@@ -59,7 +59,7 @@ class TargetTypeAccessControllerTest extends AbstractAccessControllerTest {
// verify targetTypeManagement#findByName
assertThat(targetTypeManagement.findByName(Pageable.unpaged(), permittedTargetType.getName()).getContent())
.hasSize(1).satisfies(results ->
assertThat(results.get(0).getId()).isEqualTo(permittedTargetType.getId()));
assertThat(results.get(0).getId()).isEqualTo(permittedTargetType.getId()));
assertThat(targetTypeManagement.findByName(Pageable.unpaged(), hiddenTargetType.getName())).isEmpty();
// verify targetTypeManagement#count
@@ -144,7 +144,7 @@ class TargetTypeAccessControllerTest extends AbstractAccessControllerTest {
// verify targetTypeManagement#update for readOnlyTargetType is not possible
assertThatThrownBy(() ->
targetTypeManagement.update(entityFactory.targetType().update(readOnlyTargetType.getId())
.name(readOnlyTargetType.getName() + "/new").description("newDesc")))
.name(readOnlyTargetType.getName() + "/new").description("newDesc")))
.isInstanceOf(InsufficientPermissionException.class);
}

View File

@@ -20,8 +20,6 @@ import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
import org.springframework.data.jpa.domain.Specification;
import jakarta.persistence.criteria.CriteriaQuery;
public class TestAccessControlManger {
private final Map<AccessRuleId<?>, AccessRule<?>> accessRules = new HashMap<>();
@@ -36,22 +34,20 @@ public class TestAccessControlManger {
accessRules.put(new AccessRuleId<T>(ruleClass, operation), new AccessRule<T>(specification, check));
}
public <T extends AbstractJpaBaseEntity> Specification<T> getAccessRule(final Class<T> ruleClass, final AccessController.Operation operation) {
@SuppressWarnings("unchecked")
final AccessRule<T> accessRule = (AccessRule<T>) accessRules.getOrDefault(new AccessRuleId<T>(ruleClass, operation), null);
public <T extends AbstractJpaBaseEntity> Specification<T> getAccessRule(final Class<T> ruleClass,
final AccessController.Operation operation) {
@SuppressWarnings("unchecked") final AccessRule<T> accessRule = (AccessRule<T>) accessRules.getOrDefault(
new AccessRuleId<T>(ruleClass, operation), null);
if (accessRule == null) {
return nop();
} else {
return accessRule.specification();
}
}
private static <T extends AbstractJpaBaseEntity> Specification<T> nop() {
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(AbstractJpaBaseEntity_.id), -1);
}
public <T> void assertOperation(final Class<T> ruleClass, final AccessController.Operation operation, final List<T> entities) {
@SuppressWarnings("unchecked")
final AccessRule<T> accessRule = (AccessRule<T>) accessRules.getOrDefault(new AccessRuleId<T>(ruleClass, operation), null);
@SuppressWarnings("unchecked") final AccessRule<T> accessRule = (AccessRule<T>) accessRules.getOrDefault(
new AccessRuleId<T>(ruleClass, operation), null);
if (accessRule == null) {
throw new InsufficientPermissionException("No access define - reject all");
} else {
@@ -65,6 +61,11 @@ public class TestAccessControlManger {
}
}
private static <T extends AbstractJpaBaseEntity> Specification<T> nop() {
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(AbstractJpaBaseEntity_.id), -1);
}
private record AccessRuleId<T>(Class<T> ruleClass, AccessController.Operation operation) {}
private record AccessRule<T> (Specification<T> specification, Predicate<T> checker) {}
private record AccessRule<T>(Specification<T> specification, Predicate<T> checker) {}
}

View File

@@ -20,6 +20,10 @@ import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -42,14 +46,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
/**
* Test class for {@link AutoAssignChecker}.
*
*/
@Feature("Component Tests - Repository")
@Story("Auto assign checker")
@@ -236,14 +234,6 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
verifyThatTargetsNotHaveDistributionSetAssignment(toAssignDs, targets.subList(1, 25));
}
private static Stream<Arguments> confirmationOptions() {
return Stream.of( //
Arguments.of(true, true, Status.WAIT_FOR_CONFIRMATION), //
Arguments.of(true, false, Status.RUNNING), //
Arguments.of(false, true, Status.RUNNING), //
Arguments.of(false, false, Status.RUNNING));
}
@Test
@Description("Test auto assignment of an incomplete DS to filtered targets, that causes failures")
void checkAutoAssignWithFailures() {
@@ -261,7 +251,7 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
// fail
assertThatExceptionOfType(IncompleteDistributionSetException.class).isThrownBy(() -> {
final Long filterId = targetFilterQueryManagement.create(
entityFactory.targetFilterQuery().create().name("filterA").query("id==" + targetDsFIdPref + "*"))
entityFactory.targetFilterQuery().create().name("filterA").query("id==" + targetDsFIdPref + "*"))
.getId();
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(setF.getId()));
@@ -295,71 +285,6 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
}
/**
* @param set
* the expected distribution set
* @param targets
* the targets that should have it
*/
@Step
private void verifyThatTargetsHaveDistributionSetAssignment(final DistributionSet set, final List<Target> targets,
final int count) {
final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList());
final Slice<Target> targetsAll = targetManagement.findAll(PAGE);
assertThat(targetsAll).as("Count of targets").hasSize(count);
for (final Target target : targetsAll) {
if (targetIds.contains(target.getId())) {
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId()).get())
.as("assigned DS").isEqualTo(set);
}
}
}
@Step
private void verifyThatTargetsHaveDistributionSetAssignedAndActionStatus(final DistributionSet set,
final List<Target> targets, final Action.Status status) {
final List<String> targetIds = targets.stream().map(Target::getControllerId).collect(Collectors.toList());
final List<Target> targetsWithAssignedDS = targetManagement.findByAssignedDistributionSet(PAGE, set.getId())
.getContent();
assertThat(targetsWithAssignedDS).isNotEmpty();
assertThat(targetsWithAssignedDS).allMatch(target -> targetIds.contains(target.getControllerId()));
final List<Action> actionsByDs = findActionsByDistributionSet(PAGE, set.getId())
.getContent();
assertThat(actionsByDs).hasSize(targets.size());
assertThat(actionsByDs).allMatch(action -> action.getStatus() == status);
}
@Step
private void verifyThatTargetsNotHaveDistributionSetAssignment(final DistributionSet set,
final List<Target> targets) {
final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList());
final Slice<Target> targetsAll = targetManagement.findAll(PAGE);
for (final Target target : targetsAll) {
if (targetIds.contains(target.getId())) {
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId())).isEmpty();
}
}
}
@Step
private void verifyThatCreatedActionsAreInitiatedByCurrentUser(final TargetFilterQuery targetFilterQuery,
final DistributionSet distributionSet, final List<Target> targets) {
final Set<String> targetIds = targets.stream().map(Target::getControllerId).collect(Collectors.toSet());
findActionsByDistributionSet(Pageable.unpaged(), distributionSet.getId()).stream()
.filter(a -> targetIds.contains(a.getTarget().getControllerId()))
.forEach(a -> assertThat(a.getInitiatedBy())
.as("Action should be initiated by the user who initiated the auto assignment")
.isEqualTo(targetFilterQuery.getAutoAssignInitiatedBy()));
}
@Test
@Description("Test auto assignment of a distribution set with FORCED, SOFT and DOWNLOAD_ONLY action types")
void checkAutoAssignWithDifferentActionTypes() {
@@ -389,29 +314,6 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
verifyThatTargetsHaveAssignmentActionType(ActionType.DOWNLOAD_ONLY, targetsC);
}
@Step
private List<Target> createTargetsAndAutoAssignDistSet(final String prefix, final int targetCount,
final DistributionSet distributionSet, final ActionType actionType) {
final List<Target> targets = testdataFactory.createTargets(targetCount, "target" + prefix,
prefix.concat(" description"));
targetFilterQueryManagement.create(
entityFactory.targetFilterQuery().create().name("filter" + prefix).query("id==target" + prefix + "*")
.autoAssignDistributionSet(distributionSet).autoAssignActionType(actionType));
return targets;
}
@Step
private void verifyThatTargetsHaveAssignmentActionType(final ActionType actionType, final List<Target> targets) {
final List<Action> actions = targets.stream().map(Target::getControllerId).flatMap(
controllerId -> deploymentManagement.findActionsByTarget(controllerId, PAGE).getContent().stream())
.collect(Collectors.toList());
assertThat(actions).hasSize(targets.size());
assertThat(actions).allMatch(action -> action.getActionType().equals(actionType));
}
@Test
@Description("An auto assignment target filter with weight creates actions with weights")
void actionsWithWeightAreCreated() throws Exception {
@@ -497,6 +399,100 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
assertThat(actionTargets).containsExactlyInAnyOrderElementsOf(compatibleTargets);
}
private static Stream<Arguments> confirmationOptions() {
return Stream.of( //
Arguments.of(true, true, Status.WAIT_FOR_CONFIRMATION), //
Arguments.of(true, false, Status.RUNNING), //
Arguments.of(false, true, Status.RUNNING), //
Arguments.of(false, false, Status.RUNNING));
}
/**
* @param set the expected distribution set
* @param targets the targets that should have it
*/
@Step
private void verifyThatTargetsHaveDistributionSetAssignment(final DistributionSet set, final List<Target> targets,
final int count) {
final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList());
final Slice<Target> targetsAll = targetManagement.findAll(PAGE);
assertThat(targetsAll).as("Count of targets").hasSize(count);
for (final Target target : targetsAll) {
if (targetIds.contains(target.getId())) {
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId()).get())
.as("assigned DS").isEqualTo(set);
}
}
}
@Step
private void verifyThatTargetsHaveDistributionSetAssignedAndActionStatus(final DistributionSet set,
final List<Target> targets, final Action.Status status) {
final List<String> targetIds = targets.stream().map(Target::getControllerId).collect(Collectors.toList());
final List<Target> targetsWithAssignedDS = targetManagement.findByAssignedDistributionSet(PAGE, set.getId())
.getContent();
assertThat(targetsWithAssignedDS).isNotEmpty();
assertThat(targetsWithAssignedDS).allMatch(target -> targetIds.contains(target.getControllerId()));
final List<Action> actionsByDs = findActionsByDistributionSet(PAGE, set.getId())
.getContent();
assertThat(actionsByDs).hasSize(targets.size());
assertThat(actionsByDs).allMatch(action -> action.getStatus() == status);
}
@Step
private void verifyThatTargetsNotHaveDistributionSetAssignment(final DistributionSet set,
final List<Target> targets) {
final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList());
final Slice<Target> targetsAll = targetManagement.findAll(PAGE);
for (final Target target : targetsAll) {
if (targetIds.contains(target.getId())) {
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId())).isEmpty();
}
}
}
@Step
private void verifyThatCreatedActionsAreInitiatedByCurrentUser(final TargetFilterQuery targetFilterQuery,
final DistributionSet distributionSet, final List<Target> targets) {
final Set<String> targetIds = targets.stream().map(Target::getControllerId).collect(Collectors.toSet());
findActionsByDistributionSet(Pageable.unpaged(), distributionSet.getId()).stream()
.filter(a -> targetIds.contains(a.getTarget().getControllerId()))
.forEach(a -> assertThat(a.getInitiatedBy())
.as("Action should be initiated by the user who initiated the auto assignment")
.isEqualTo(targetFilterQuery.getAutoAssignInitiatedBy()));
}
@Step
private List<Target> createTargetsAndAutoAssignDistSet(final String prefix, final int targetCount,
final DistributionSet distributionSet, final ActionType actionType) {
final List<Target> targets = testdataFactory.createTargets(targetCount, "target" + prefix,
prefix.concat(" description"));
targetFilterQueryManagement.create(
entityFactory.targetFilterQuery().create().name("filter" + prefix).query("id==target" + prefix + "*")
.autoAssignDistributionSet(distributionSet).autoAssignActionType(actionType));
return targets;
}
@Step
private void verifyThatTargetsHaveAssignmentActionType(final ActionType actionType, final List<Target> targets) {
final List<Action> actions = targets.stream().map(Target::getControllerId).flatMap(
controllerId -> deploymentManagement.findActionsByTarget(controllerId, PAGE).getContent().stream())
.collect(Collectors.toList());
assertThat(actions).hasSize(targets.size());
assertThat(actions).allMatch(action -> action.getActionType().equals(actionType));
}
private Slice<Action> findActionsByDistributionSet(final Pageable pageable, final long distributionSetId) {
return actionRepository
.findAll(ActionSpecifications.byDistributionSetId(distributionSetId), pageable)

View File

@@ -11,13 +11,19 @@ package org.eclipse.hawkbit.repository.jpa.autoassign;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.ContextAware;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
@@ -36,14 +42,11 @@ import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.SliceImpl;
import org.springframework.transaction.PlatformTransactionManager;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Unit Tests - Repository")
@Story("Auto assign checker")
@ExtendWith(MockitoExtension.class)
class AutoAssignCheckerTest {
@Mock
private TargetFilterQueryManagement targetFilterQueryManagement;
@Mock
@@ -86,13 +89,6 @@ class AutoAssignCheckerTest {
Mockito.verifyNoMoreInteractions(deploymentManagement);
}
private ArgumentMatcher<List<DeploymentRequest>> deployReqMatcher(final String target, final long ds) {
return requests -> {
final DeploymentRequest request = requests.get(0);
return requests.size() == 1 && request.getDistributionSetId() == ds && request.getControllerId() == target;
};
}
private static TargetFilterQuery mockFilterQuery(final long dsId) {
final DistributionSet ds = mock(DistributionSet.class);
when(ds.getId()).thenReturn(dsId);
@@ -104,12 +100,6 @@ class AutoAssignCheckerTest {
return filter;
}
private void mockRunningAsNonSystem() {
when(contextAware.getCurrentTenant()).thenReturn(getRandomString());
when(contextAware.runAsTenantAsUser(any(String.class), any(String.class), any(TenantAware.TenantRunner.class)))
.thenAnswer(i -> ((TenantAware.TenantRunner)i.getArgument(2)).run());
}
private static long getRandomLong() {
return ThreadLocalRandom.current().nextLong();
}
@@ -118,4 +108,17 @@ class AutoAssignCheckerTest {
return UUID.randomUUID().toString();
}
private ArgumentMatcher<List<DeploymentRequest>> deployReqMatcher(final String target, final long ds) {
return requests -> {
final DeploymentRequest request = requests.get(0);
return requests.size() == 1 && request.getDistributionSetId() == ds && request.getControllerId() == target;
};
}
private void mockRunningAsNonSystem() {
when(contextAware.getCurrentTenant()).thenReturn(getRandomString());
when(contextAware.runAsTenantAsUser(any(String.class), any(String.class), any(TenantAware.TenantRunner.class)))
.thenAnswer(i -> ((TenantAware.TenantRunner) i.getArgument(2)).run());
}
}

View File

@@ -17,6 +17,9 @@ import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationPrope
import java.util.Arrays;
import java.util.stream.Collectors;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -25,13 +28,8 @@ import org.eclipse.hawkbit.repository.model.Target;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test class for {@link AutoActionCleanup}.
*
*/
@Feature("Component Tests - Repository")
@Story("Action cleanup handler")

View File

@@ -14,19 +14,17 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.support.locks.LockRegistry;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test class for {@link AutoCleanupScheduler}.
*
*/
@Feature("Component Tests - Repository")
@Story("Auto cleanup scheduler")

View File

@@ -15,6 +15,9 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.assertj.core.api.Assertions;
import org.eclipse.hawkbit.repository.event.TenantAwareEvent;
import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
@@ -44,10 +47,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Entity Events")
@SpringBootTest(classes = { RepositoryTestConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.NONE)

View File

@@ -11,16 +11,15 @@ package org.eclipse.hawkbit.repository.jpa.management;
import static org.assertj.core.api.Assertions.assertThat;
import org.awaitility.Awaitility;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import java.time.Duration;
import org.awaitility.Awaitility;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.junit.jupiter.api.Test;
@Feature("Unit Tests - Repository")
@Story("Deployment Management")

View File

@@ -27,6 +27,9 @@ import java.util.concurrent.Callable;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
@@ -56,10 +59,6 @@ import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test class for {@link ArtifactManagement}.
*/
@@ -280,7 +279,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
final int artifactSize = 5 * 1024;
try (final InputStream inputStream1 = new RandomGeneratedInputStream(artifactSize);
final InputStream inputStream2 = new RandomGeneratedInputStream(artifactSize)) {
final InputStream inputStream2 = new RandomGeneratedInputStream(artifactSize)) {
final Artifact artifact1 = createArtifactForSoftwareModule("file1", sm.getId(), artifactSize, inputStream1);
final Artifact artifact2 = createArtifactForSoftwareModule("file2", sm2.getId(), artifactSize,
@@ -294,10 +293,10 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
assertThat(
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifact1.getSha1Hash()))
.isNotNull();
.isNotNull();
assertThat(
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifact2.getSha1Hash()))
.isNotNull();
.isNotNull();
artifactManagement.delete(artifact1.getId());
@@ -305,15 +304,15 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
assertThat(
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifact1.getSha1Hash()))
.isNull();
.isNull();
assertThat(
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifact2.getSha1Hash()))
.isNotNull();
.isNotNull();
artifactManagement.delete(artifact2.getId());
assertThat(
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifact2.getSha1Hash()))
.isNull();
.isNull();
assertThat(artifactRepository.findAll()).hasSize(0);
}
@@ -345,19 +344,19 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
assertThat(
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifact1.getSha1Hash()))
.isNotNull();
.isNotNull();
artifactManagement.delete(artifact1.getId());
assertThat(
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifact1.getSha1Hash()))
.isNotNull();
.isNotNull();
assertThat(artifactRepository.findAll()).hasSize(1);
assertThat(artifactRepository.existsById(artifact1.getId())).isFalse();
artifactManagement.delete(artifact2.getId());
assertThat(
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifact1.getSha1Hash()))
.isNull();
.isNull();
assertThat(artifactRepository.findAll()).hasSize(0);
}
}
@@ -422,7 +421,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
assertThat(runAsTenant(tenant1, () -> artifactRepository
.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(artifactTenant2.getSha1Hash(), tenant2)))
.isLessThanOrEqualTo(1);
.isLessThanOrEqualTo(1);
runAsTenant(tenant2, () -> {
artifactRepository.deleteById(artifactTenant2.getId());
return null;
@@ -579,6 +578,10 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
}
}
private static byte[] randomBytes(final int len) {
return RandomStringUtils.randomAlphanumeric(len).getBytes();
}
private DbArtifactHash calcHashes(final byte[] input) throws NoSuchAlgorithmException {
final String sha1Hash = toBase16Hash("SHA1", input);
final String md5Hash = toBase16Hash("MD5", input);
@@ -606,10 +609,6 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
return artifactManagement.create(new ArtifactUpload(inputStream, moduleId, filename, false, artifactSize));
}
private static byte[] randomBytes(final int len) {
return RandomStringUtils.randomAlphanumeric(len).getBytes();
}
private <T> T runAsTenant(final String tenant, final Callable<T> callable) throws Exception {
return SecurityContextSwitch.runAs(SecurityContextSwitch.withUserAndTenantAllSpPermissions("user", tenant), callable);
}

View File

@@ -19,6 +19,9 @@ import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.exception.AutoConfirmationAlreadyActiveException;
import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -29,10 +32,6 @@ import org.eclipse.hawkbit.repository.model.DeploymentRequestBuilder;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@@ -40,7 +39,6 @@ import org.junit.jupiter.params.provider.MethodSource;
/**
* Test class testing the functionality of triggering a deployment of
* {@link DistributionSet}s to {@link Target}s with AutoConfirmation active.
*
*/
@Feature("Component Tests - Repository")
@Story("Confirmation Management")
@@ -140,9 +138,9 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
assertThat(newAction.getStatus()).isEqualTo(Status.RUNNING);
assertThatThrownBy(() -> confirmationManagement.confirmAction(actions.get(0).getId(), null, null))
.isInstanceOf(InvalidConfirmationFeedbackException.class)
.matches(e -> ((InvalidConfirmationFeedbackException) e)
.getReason() == InvalidConfirmationFeedbackException.Reason.NOT_AWAITING_CONFIRMATION);
.isInstanceOf(InvalidConfirmationFeedbackException.class)
.matches(e -> ((InvalidConfirmationFeedbackException) e)
.getReason() == InvalidConfirmationFeedbackException.Reason.NOT_AWAITING_CONFIRMATION);
}
@Test
@@ -152,9 +150,9 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
final Action action = prepareFinishedUpdate();
assertThatThrownBy(() -> confirmationManagement.confirmAction(action.getId(), null, null))
.isInstanceOf(InvalidConfirmationFeedbackException.class)
.matches(e -> ((InvalidConfirmationFeedbackException) e)
.getReason() == InvalidConfirmationFeedbackException.Reason.ACTION_CLOSED);
.isInstanceOf(InvalidConfirmationFeedbackException.class)
.matches(e -> ((InvalidConfirmationFeedbackException) e)
.getReason() == InvalidConfirmationFeedbackException.Reason.ACTION_CLOSED);
}
@Test
@@ -197,7 +195,7 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
final List<Action> actions = assignDistributionSets(
Arrays.asList(toDeploymentRequest(controllerId, dsId), toDeploymentRequest(controllerId, dsId2)))
.stream().flatMap(s -> s.getAssignedEntity().stream()).collect(Collectors.toList());
.stream().flatMap(s -> s.getAssignedEntity().stream()).collect(Collectors.toList());
assertThat(actions).hasSize(2);
assertThat(confirmationManagement.findActiveActionsWaitingConfirmation(controllerId)).hasSize(2)
@@ -276,11 +274,6 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
verifyAutoConfirmationIsDisabled(controllerId);
}
private static Stream<Arguments> getAutoConfirmationArguments() {
return Stream.of(Arguments.of("TestUser", "TestRemark"), Arguments.of("TestUser", null),
Arguments.of(null, "TestRemark"), Arguments.of(null, null));
}
@Test
@Description("Verify activating already active auto confirmation will throw exception.")
void verifyActivateAlreadyActiveAutoConfirmationThrowException() {
@@ -305,13 +298,18 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
verifyAutoConfirmationIsDisabled(controllerId);
}
private void verifyAutoConfirmationIsDisabled(final String controllerId) {
assertThat(targetManagement.getByControllerID(controllerId))
.hasValueSatisfying(target -> assertThat(target.getAutoConfirmationStatus()).isNull());
private static Stream<Arguments> getAutoConfirmationArguments() {
return Stream.of(Arguments.of("TestUser", "TestRemark"), Arguments.of("TestUser", null),
Arguments.of(null, "TestRemark"), Arguments.of(null, null));
}
private static DeploymentRequest toDeploymentRequest(final String controllerId, final Long distributionSetId) {
return new DeploymentRequestBuilder(controllerId, distributionSetId).setConfirmationRequired(true).build();
}
private void verifyAutoConfirmationIsDisabled(final String controllerId) {
assertThat(targetManagement.getByControllerID(controllerId))
.hasValueSatisfying(target -> assertThat(target.getAutoConfirmationStatus()).isNull());
}
}

View File

@@ -30,15 +30,18 @@ import java.util.stream.Stream;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.assertj.core.api.Assertions;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
@@ -92,10 +95,6 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort.Direction;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test class testing the functionality of triggering a deployment of {@link DistributionSet}s to {@link Target}s.
*/
@@ -106,6 +105,44 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
private static final boolean STATE_ACTIVE = true;
private static final boolean STATE_INACTIVE = false;
@Test
@Description("Tests that an exception is thrown when a target is assigned to an incomplete distribution set")
public void verifyAssignTargetsToIncompleteDistribution() {
final DistributionSet distributionSet = testdataFactory.createIncompleteDistributionSet();
final Target target = testdataFactory.createTarget();
assertThatExceptionOfType(IncompleteDistributionSetException.class)
.as("Incomplete distributionSet should throw an exception")
.isThrownBy(() -> assignDistributionSet(distributionSet, target));
}
@Test
@Description("Tests that an exception is thrown when a target is assigned to an invalidated distribution set")
public void verifyAssignTargetsToInvalidDistribution() {
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
final Target target = testdataFactory.createTarget();
assertThatExceptionOfType(InvalidDistributionSetException.class)
.as("Invalid distributionSet should throw an exception")
.isThrownBy(() -> assignDistributionSet(distributionSet, target));
}
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight) {
return createAssignmentRequests(distributionSets, targets, weight, false);
}
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight, final boolean confirmationRequired) {
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
distributionSets.forEach(ds -> targets.forEach(target -> deploymentRequests
.add(DeploymentManagement.deploymentRequest(target.getControllerId(), ds.getId()).setWeight(weight)
.setConfirmationRequired(confirmationRequired).build())));
return deploymentRequests;
}
@Test
@Description("Verifies that management get access react as specified on calls for non existing entities by means " +
"of Optional not present.")
@@ -279,7 +316,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) }) // implicit lock })
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) })
// implicit lock })
void multiAssigmentHistoryOverMultiplePagesResultsInTwoActiveAction() {
final DistributionSet cancelDs = testdataFactory.createDistributionSet("Canceled DS", "1.0",
@@ -450,24 +488,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
.isThrownBy(() -> deploymentManagement.forceQuitAction(assigningAction.getId()));
}
private JpaAction assignSet(final Target target, final DistributionSet ds) {
assignDistributionSet(ds.getId(), target.getControllerId());
implicitLock(ds);
assertThat(targetManagement.getByControllerID(target.getControllerId()).get().getUpdateStatus())
.as("wrong update status").isEqualTo(TargetUpdateStatus.PENDING);
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId())).as("wrong assigned ds")
.contains(ds);
final JpaAction action = actionRepository
.findAll(
(root, query, cb) ->
cb.and(
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.id), target.getId()),
cb.equal(root.get(JpaAction_.distributionSet).get(JpaDistributionSet_.id), ds.getId())),
PAGE).getContent().get(0);
assertThat(action).as("action should not be null").isNotNull();
return action;
}
@Test
@Description("Simple offline deployment of a distribution set to a list of targets. Verifies that offline assigment "
+ "is correctly executed for targets that do not have a running update already. Those are ignored.")
@@ -617,20 +637,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertDsExclusivelyAssignedToTargets(targets, ds1.getId(), STATE_ACTIVE, RUNNING);
}
private void assertDsExclusivelyAssignedToTargets(final List<Target> targets, final long dsId, final boolean active,
final Status status) {
final List<Action> assignment = findActionsByDistributionSet(PAGE, dsId).getContent();
final String currentUsername = tenantAware.getCurrentUsername();
assertThat(assignment).hasSize(10).allMatch(action -> action.isActive() == active)
.as("Is assigned to DS " + dsId).allMatch(action -> action.getDistributionSet().getId().equals(dsId))
.as("State is " + status).allMatch(action -> action.getStatus() == status)
.as("Initiated by " + currentUsername).allMatch(a -> a.getInitiatedBy().equals(currentUsername));
final long[] targetIds = targets.stream().mapToLong(Target::getId).toArray();
assertThat(targetIds).as("All targets represented in assignment").containsExactlyInAnyOrder(
assignment.stream().mapToLong(action -> action.getTarget().getId()).toArray());
}
@Test
@Description("Assign multiple DSs to a single Target in one request in multiassignment mode.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@@ -699,20 +705,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
});
}
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight) {
return createAssignmentRequests(distributionSets, targets, weight, false);
}
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight, final boolean confirmationRequired) {
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
distributionSets.forEach(ds -> targets.forEach(target -> deploymentRequests
.add(DeploymentManagement.deploymentRequest(target.getControllerId(), ds.getId()).setWeight(weight)
.setConfirmationRequired(confirmationRequired).build())));
return deploymentRequests;
}
@Test
@Description("A Request resulting in multiple assignments to a single target is only allowed when multiassignment is enabled.")
void multipleAssignmentsToTargetOnlyAllowedInMultiAssignMode() {
@@ -741,7 +733,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final DistributionSet createdDs = testdataFactory.createDistributionSet();
final List<String> knownTargetIds = new ArrayList<>();
knownTargetIds.add( "1");
knownTargetIds.add("1");
knownTargetIds.add("2");
testdataFactory.createTargets(knownTargetIds.toArray(new String[0]));
@@ -898,16 +890,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
});
}
private List<DistributionSetAssignmentResult> assignDistributionSetToTargets(final DistributionSet distributionSet,
final Iterable<String> targetIds, final boolean confirmationRequired) {
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
for (final String controllerId : targetIds) {
deploymentRequests.add(new DeploymentRequest(controllerId, distributionSet.getId(), ActionType.FORCED, 0,
null, null, null, null, confirmationRequired));
}
return deploymentManagement.assignDistributionSets(deploymentRequests);
}
@Test
@Description("Duplicate Assignments are removed from a request when multiassignment is disabled, otherwise not")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@@ -936,10 +918,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
.isEqualTo(1);
}
private int getResultingActionCount(final List<DistributionSetAssignmentResult> results) {
return results.stream().map(DistributionSetAssignmentResult::getTotal).reduce(0, Integer::sum);
}
@Test
@Description("An assignment request is not accepted if it would lead to a target exceeding the max actions per target quota.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@@ -1033,7 +1011,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
* test a simple deployment by calling the
* {@link TargetRepository#assignDistributionSet(DistributionSet, Iterable)} and
* checking the active action and the action history of the targets.
*
*/
@Test
@Description("Simple deployment or distribution set to target assignment test.")
@@ -1319,7 +1296,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(allFoundDS.size()).as("no ds should be founded").isZero();
assertThat(distributionSetRepository.findAll(SpecificationsBuilder.combineWithAnd(Arrays
.asList(DistributionSetSpecification.isDeleted(true), DistributionSetSpecification.isCompleted(true))),
.asList(DistributionSetSpecification.isDeleted(true), DistributionSetSpecification.isCompleted(true))),
PAGE).getContent()).as("wrong size of founded ds").hasSize(noOfDistributionSets);
for (final DistributionSet ds : deploymentResult.getDistributionSets()) {
@@ -1335,7 +1312,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
allFoundDS = distributionSetManagement.findByCompleted(pageRequest, true).getContent();
assertThat(allFoundDS.size()).as("no ds should be founded").isZero();
assertThat(distributionSetRepository.findAll(SpecificationsBuilder.combineWithAnd(Arrays
.asList(DistributionSetSpecification.isDeleted(true), DistributionSetSpecification.isCompleted(true))),
.asList(DistributionSetSpecification.isDeleted(true), DistributionSetSpecification.isCompleted(true))),
PAGE).getContent()).as("wrong size of founded ds").hasSize(noOfDistributionSets);
}
@@ -1549,30 +1526,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(distributionSetRepository.findAll()).hasSize(1);
}
@Test
@Description("Tests that an exception is thrown when a target is assigned to an incomplete distribution set")
public void verifyAssignTargetsToIncompleteDistribution() {
final DistributionSet distributionSet = testdataFactory.createIncompleteDistributionSet();
final Target target = testdataFactory.createTarget();
assertThatExceptionOfType(IncompleteDistributionSetException.class)
.as("Incomplete distributionSet should throw an exception")
.isThrownBy(() -> assignDistributionSet(distributionSet, target));
}
@Test
@Description("Tests that an exception is thrown when a target is assigned to an invalidated distribution set")
public void verifyAssignTargetsToInvalidDistribution() {
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
final Target target = testdataFactory.createTarget();
assertThatExceptionOfType(InvalidDistributionSetException.class)
.as("Invalid distributionSet should throw an exception")
.isThrownBy(() -> assignDistributionSet(distributionSet, target));
}
@Test
@Description("Verify that the DistributionSet assignments work for multiple targets of the same target type within the same request.")
void verifyDSAssignmentForMultipleTargetsWithSameTargetType() {
@@ -1661,6 +1614,52 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests));
}
private JpaAction assignSet(final Target target, final DistributionSet ds) {
assignDistributionSet(ds.getId(), target.getControllerId());
implicitLock(ds);
assertThat(targetManagement.getByControllerID(target.getControllerId()).get().getUpdateStatus())
.as("wrong update status").isEqualTo(TargetUpdateStatus.PENDING);
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId())).as("wrong assigned ds")
.contains(ds);
final JpaAction action = actionRepository
.findAll(
(root, query, cb) ->
cb.and(
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.id), target.getId()),
cb.equal(root.get(JpaAction_.distributionSet).get(JpaDistributionSet_.id), ds.getId())),
PAGE).getContent().get(0);
assertThat(action).as("action should not be null").isNotNull();
return action;
}
private void assertDsExclusivelyAssignedToTargets(final List<Target> targets, final long dsId, final boolean active,
final Status status) {
final List<Action> assignment = findActionsByDistributionSet(PAGE, dsId).getContent();
final String currentUsername = tenantAware.getCurrentUsername();
assertThat(assignment).hasSize(10).allMatch(action -> action.isActive() == active)
.as("Is assigned to DS " + dsId).allMatch(action -> action.getDistributionSet().getId().equals(dsId))
.as("State is " + status).allMatch(action -> action.getStatus() == status)
.as("Initiated by " + currentUsername).allMatch(a -> a.getInitiatedBy().equals(currentUsername));
final long[] targetIds = targets.stream().mapToLong(Target::getId).toArray();
assertThat(targetIds).as("All targets represented in assignment").containsExactlyInAnyOrder(
assignment.stream().mapToLong(action -> action.getTarget().getId()).toArray());
}
private List<DistributionSetAssignmentResult> assignDistributionSetToTargets(final DistributionSet distributionSet,
final Iterable<String> targetIds, final boolean confirmationRequired) {
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
for (final String controllerId : targetIds) {
deploymentRequests.add(new DeploymentRequest(controllerId, distributionSet.getId(), ActionType.FORCED, 0,
null, null, null, null, confirmationRequired));
}
return deploymentManagement.assignDistributionSets(deploymentRequests);
}
private int getResultingActionCount(final List<DistributionSetAssignmentResult> results) {
return results.stream().map(DistributionSetAssignmentResult::getTotal).reduce(0, Integer::sum);
}
/**
* Helper methods that creates 2 lists of targets and a list of distribution
* sets.
@@ -1668,18 +1667,12 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
* <b>All created distribution sets are assigned to all targets of the target
* list deployedTargets.</b>
*
* @param undeployedTargetPrefix
* prefix to be used as target controller prefix
* @param noOfUndeployedTargets
* number of targets which remain undeployed
* @param deployedTargetPrefix
* prefix to be used as target controller prefix
* @param noOfDeployedTargets
* number of targets to which the created distribution sets assigned
* @param noOfDistributionSets
* number of distribution sets
* @param distributionSetPrefix
* prefix for the created distribution sets
* @param undeployedTargetPrefix prefix to be used as target controller prefix
* @param noOfUndeployedTargets number of targets which remain undeployed
* @param deployedTargetPrefix prefix to be used as target controller prefix
* @param noOfDeployedTargets number of targets to which the created distribution sets assigned
* @param noOfDistributionSets number of distribution sets
* @param distributionSetPrefix prefix for the created distribution sets
* @return the {@link DeploymentResult} containing all created targets, the
* distribution sets, the corresponding IDs for later evaluation in
* tests
@@ -1720,6 +1713,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
}
private static class DeploymentResult {
final List<Long> deployedTargetIDs = new ArrayList<>();
final List<Long> undeployedTargetIDs = new ArrayList<>();
final List<Long> distributionSetIDs = new ArrayList<>();

View File

@@ -15,9 +15,11 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.util.Collections;
import java.util.List;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
@@ -34,16 +36,11 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.springframework.data.repository.query.Param;
/**
* Test class testing the functionality of invalidating a
* {@link DistributionSet}
*
*/
@Feature("Component Tests - Repository")
@Story("Distribution set invalidation management")
@@ -104,7 +101,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
// if status is pending, the assignment has not been canceled
assertThat(
targetRepository.findById(invalidationTestData.getTargets().get(0).getId()).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.PENDING);
.isEqualTo(TargetUpdateStatus.PENDING);
assertThat(findActionsByTarget(target).size()).isEqualTo(1);
assertThat(findActionsByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
}
@@ -140,17 +137,6 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
}
}
private void assertNoScheduledActionsExist(final Rollout rollout) {
assertThat(
actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), Status.SCHEDULED).getTotalElements())
.isZero();
}
private void assertRolloutGroupsAreFinished(final Rollout rollout) {
assertThat(rolloutGroupRepository.findByRolloutId(rollout.getId(), PAGE))
.allMatch(rolloutGroup -> rolloutGroup.getStatus().equals(RolloutGroupStatus.FINISHED));
}
@Test
@Description("Verify invalidation of distribution sets that removes distribution sets from auto assignments, stops rollouts and cancels assignments")
void verifyInvalidateDistributionSetStopAll() {
@@ -196,8 +182,8 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
void verifyInvalidateInvalidatedDistributionSetDontThrowsException() {
final DistributionSet distributionSet = testdataFactory.createAndInvalidateDistributionSet();
distributionSetInvalidationManagement.invalidateDistributionSet(
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
CancelationType.SOFT, true));
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
CancelationType.SOFT, true));
}
@Test
@@ -234,7 +220,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
false));
assertThat(
distributionSetRepository.findById(invalidationTestData.getDistributionSet().getId()).get().isValid())
.isFalse();
.isFalse();
}
@Test
@@ -249,7 +235,18 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
true));
assertThat(
distributionSetRepository.findById(invalidationTestData.getDistributionSet().getId()).get().isValid())
.isFalse();
.isFalse();
}
private void assertNoScheduledActionsExist(final Rollout rollout) {
assertThat(
actionRepository.findByRolloutIdAndStatus(PAGE, rollout.getId(), Status.SCHEDULED).getTotalElements())
.isZero();
}
private void assertRolloutGroupsAreFinished(final Rollout rollout) {
assertThat(rolloutGroupRepository.findByRolloutId(rollout.getId(), PAGE))
.allMatch(rolloutGroup -> rolloutGroup.getStatus().equals(RolloutGroupStatus.FINISHED));
}
private InvalidationTestData createInvalidationTestData(final String testName) {
@@ -264,7 +261,20 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
return new InvalidationTestData(distributionSet, targets, targetFilterQuery, rollout);
}
private void assertDistributionSetInvalidationCount(
final DistributionSetInvalidationCount distributionSetInvalidationCount,
final long expectedAutoAssignmentCount, final long expectedActionCount, final long expectedRolloutCount) {
assertThat(distributionSetInvalidationCount.getAutoAssignmentCount()).isEqualTo(expectedAutoAssignmentCount);
assertThat(distributionSetInvalidationCount.getActionCount()).isEqualTo(expectedActionCount);
assertThat(distributionSetInvalidationCount.getRolloutsCount()).isEqualTo(expectedRolloutCount);
}
private List<JpaAction> findActionsByTarget(@Param("target") Target target) { // order by id ?
return actionRepository.findAll(ActionSpecifications.byTargetControllerId(target.getControllerId()));
}
private static class InvalidationTestData {
private final DistributionSet distributionSet;
private final List<Target> targets;
private final TargetFilterQuery targetFilterQuery;
@@ -295,16 +305,4 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
return rollout;
}
}
private void assertDistributionSetInvalidationCount(
final DistributionSetInvalidationCount distributionSetInvalidationCount,
final long expectedAutoAssignmentCount, final long expectedActionCount, final long expectedRolloutCount) {
assertThat(distributionSetInvalidationCount.getAutoAssignmentCount()).isEqualTo(expectedAutoAssignmentCount);
assertThat(distributionSetInvalidationCount.getActionCount()).isEqualTo(expectedActionCount);
assertThat(distributionSetInvalidationCount.getRolloutsCount()).isEqualTo(expectedRolloutCount);
}
private List<JpaAction> findActionsByTarget(@Param("target") Target target) { // order by id ?
return actionRepository.findAll(ActionSpecifications.byTargetControllerId(target.getControllerId()));
}
}

View File

@@ -28,6 +28,10 @@ import java.util.stream.Stream;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.assertj.core.api.Condition;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
@@ -74,20 +78,16 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
/**
* {@link DistributionSetManagement} tests.
*
*/
@Feature("Component Tests - Repository")
@Story("DistributionSet Management")
class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
public static final String TAG1_NAME = "Tag1";
@Autowired
RepositoryProperties repositoryProperties;
@Test
@Description("Verifies that management get access react as specified on calls for non existing entities by means "
@@ -213,84 +213,6 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
createAndUpdateDistributionSetWithInvalidVersion(set);
}
@Step
private void createAndUpdateDistributionSetWithInvalidDescription(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long description should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version("a").description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with invalid description should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version("a").description(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long description should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with invalid characters should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateDistributionSetWithInvalidName(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long name should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().version("a")
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too short name should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name("")));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with invalid characters in name should not be created")
.isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long name should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with invalid characters should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too short name should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).name("")));
}
@Step
private void createAndUpdateDistributionSetWithInvalidVersion(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long version should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version(RandomStringUtils.randomAlphanumeric(NamedVersionedEntity.VERSION_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too short version should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("a").version("")));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long version should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.version(RandomStringUtils.randomAlphanumeric(NamedVersionedEntity.VERSION_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too short version should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).version("")));
}
@Test
@Description("Ensures that it is not possible to create a DS that already exists (unique constraint is on name,version for DS).")
void createDuplicateDistributionSetsFailsWithException() {
@@ -333,6 +255,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
final List<DistributionSet> sets = distributionSetManagement.create(creates);
assertThat(sets).as("Type should be equal to default type of tenant").are(new Condition<DistributionSet>() {
@Override
public boolean matches(final DistributionSet value) {
return value.getType().equals(systemManagement.getTenantMetadata().getDefaultDsType());
@@ -484,7 +407,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
// update data
assertThatThrownBy(
() -> distributionSetManagement.assignSoftwareModules(set.getId(), Set.of(module.getId())))
.isInstanceOf(UnsupportedSoftwareModuleForThisDistributionSetException.class);
.isInstanceOf(UnsupportedSoftwareModuleForThisDistributionSetException.class);
}
@Test
@@ -772,223 +695,6 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
validateDeletedAndCompletedAndTypeAndSearchTextAndTag(dsGroup2, dsTagA, dsGroup2Prefix);
}
@Step
private void validateFindAll(final List<DistributionSet> expectedDistributionsets) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder(), expectedDistributionsets);
}
@Step
private void validateDeleted(final DistributionSet deletedDistributionSet, final int notDeletedSize) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isDeleted(Boolean.TRUE),
singletonList(deletedDistributionSet));
assertThatFilterHasSizeAndDoesNotContainDistributionSet(
DistributionSetFilter.builder().isDeleted(Boolean.FALSE), notDeletedSize, deletedDistributionSet);
}
@Step
private void validateCompleted(final DistributionSet dsIncomplete, final int completedSize) {
assertThatFilterHasSizeAndDoesNotContainDistributionSet(
DistributionSetFilter.builder().isComplete(Boolean.TRUE), completedSize, dsIncomplete);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.FALSE), singletonList(dsIncomplete));
}
@Step
private void validateType(final DistributionSetType newType, final DistributionSet dsNewType,
final int standardDsTypeSize) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().typeId(newType.getId()),
singletonList(dsNewType));
assertThatFilterHasSizeAndDoesNotContainDistributionSet(
DistributionSetFilter.builder().typeId(standardDsType.getId()), standardDsTypeSize, dsNewType);
}
@Step
private void validateSearchText(final List<DistributionSet> allDistributionSets, final String dsNamePrefix) {
final List<DistributionSet> withTestNamePrefix = allDistributionSets.stream()
.filter(ds -> ds.getName().startsWith(dsNamePrefix)).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(dsNamePrefix),
withTestNamePrefix);
final List<DistributionSet> withTestNameExact = withTestNamePrefix.stream()
.filter(ds -> ds.getName().equals(dsNamePrefix)).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().searchText(dsNamePrefix + ":"), withTestNameExact);
final List<DistributionSet> withTestNameExactAndVersionPrefix = withTestNameExact.stream()
.filter(ds -> ds.getVersion().startsWith("1")).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().searchText(dsNamePrefix + ":1"),
withTestNameExactAndVersionPrefix);
final List<DistributionSet> dsWithExactNameAndVersion = withTestNameExactAndVersionPrefix.stream()
.filter(ds -> ds.getVersion().equals("1.0.0")).collect(Collectors.toList());
assertThat(dsWithExactNameAndVersion).hasSize(1);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().searchText(dsNamePrefix + ":1.0.0"), dsWithExactNameAndVersion);
final List<DistributionSet> withVersionPrefix = allDistributionSets.stream()
.filter(ds -> ds.getVersion().startsWith("1.0.")).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":1.0."),
withVersionPrefix);
final List<DistributionSet> withVersionExact = withVersionPrefix.stream()
.filter(ds -> ds.getVersion().equals("1.0.0")).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":1.0.0"),
withVersionExact);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":"),
allDistributionSets);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(" : "),
allDistributionSets);
}
@Step
private void validateTags(final DistributionSetTag dsTagA, final DistributionSetTag dsTagB,
final DistributionSetTag dsTagC, final List<DistributionSet> dsWithTagA,
final List<DistributionSet> dsWithTagB) {
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().tagNames(singletonList(dsTagA.getName())), dsWithTagA);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().tagNames(singletonList(dsTagB.getName())), dsWithTagB);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().tagNames(Arrays.asList(dsTagA.getName(), dsTagB.getName())),
dsWithTagA);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().tagNames(Arrays.asList(dsTagC.getName(), dsTagB.getName())),
dsWithTagB);
assertThatFilterDoesNotContainAnyDistributionSet(
DistributionSetFilter.builder().tagNames(singletonList(dsTagC.getName())));
}
@Step
private void validateDeletedAndCompleted(final List<DistributionSet> completedStandardType,
final DistributionSet dsNewType, final DistributionSet dsDeleted) {
final List<DistributionSet> completedNotDeleted = new ArrayList<>(completedStandardType);
completedNotDeleted.add(dsNewType);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).isDeleted(Boolean.FALSE),
completedNotDeleted);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).isDeleted(Boolean.TRUE),
singletonList(dsDeleted));
assertThatFilterDoesNotContainAnyDistributionSet(
DistributionSetFilter.builder().isComplete(Boolean.FALSE).isDeleted(Boolean.TRUE));
}
@Step
private void validateDeletedAndCompletedAndType(final List<DistributionSet> deletedAndCompletedAndStandardType,
final DistributionSet dsDeleted, final DistributionSetType newType, final DistributionSet dsNewType) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isDeleted(Boolean.FALSE)
.isComplete(Boolean.TRUE).typeId(standardDsType.getId()), deletedAndCompletedAndStandardType);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isComplete(Boolean.TRUE)
.typeId(standardDsType.getId()).isDeleted(Boolean.TRUE), singletonList(dsDeleted));
assertThatFilterDoesNotContainAnyDistributionSet(DistributionSetFilter.builder().isDeleted(Boolean.TRUE)
.isComplete(Boolean.FALSE).typeId(standardDsType.getId()));
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).typeId(newType.getId()),
singletonList(dsNewType));
}
@Step
private void validateDeletedAndCompletedAndTypeAndSearchText(
final List<DistributionSet> completedAndStandardTypeAndSearchText, final DistributionSetType newType,
final String text) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isDeleted(Boolean.FALSE)
.isComplete(Boolean.TRUE).typeId(standardDsType.getId()).searchText(text),
completedAndStandardTypeAndSearchText);
assertThatFilterDoesNotContainAnyDistributionSet(DistributionSetFilter.builder().isComplete(Boolean.TRUE)
.isDeleted(Boolean.TRUE).typeId(standardDsType.getId()).searchText(text + ":"));
assertThatFilterDoesNotContainAnyDistributionSet(
DistributionSetFilter.builder().typeId(standardDsType.getId()).searchText(text)
.isComplete(Boolean.FALSE).isDeleted(Boolean.FALSE));
assertThatFilterDoesNotContainAnyDistributionSet(DistributionSetFilter.builder().typeId(newType.getId())
.searchText(text).isComplete(Boolean.TRUE).isDeleted(Boolean.FALSE));
}
@Step
private void validateDeletedAndCompletedAndTypeAndSearchText(
final List<DistributionSet> completedAndNotDeletedStandardTypeAndFilterString,
final DistributionSet dsDeleted, final DistributionSet dsInComplete, final DistributionSet dsNewType,
final DistributionSetType newType, final String filterString) {
final List<DistributionSet> completedAndStandardTypeAndFilterString = new ArrayList<>(
completedAndNotDeletedStandardTypeAndFilterString);
completedAndStandardTypeAndFilterString.add(dsDeleted);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isComplete(Boolean.TRUE)
.typeId(standardDsType.getId()).searchText(filterString),
completedAndStandardTypeAndFilterString);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).isDeleted(Boolean.FALSE)
.typeId(standardDsType.getId()).searchText(filterString),
completedAndNotDeletedStandardTypeAndFilterString);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isComplete(Boolean.TRUE)
.isDeleted(Boolean.TRUE).typeId(standardDsType.getId()).searchText(filterString),
singletonList(dsDeleted));
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().typeId(standardDsType.getId()).searchText(filterString)
.isComplete(Boolean.FALSE).isDeleted(Boolean.FALSE),
singletonList(dsInComplete));
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().typeId(newType.getId())
.searchText(filterString).isComplete(Boolean.TRUE).isDeleted(Boolean.FALSE),
singletonList(dsNewType));
}
@Step
private void validateDeletedAndCompletedAndTypeAndSearchTextAndTag(
final List<DistributionSet> completedAndStandartTypeAndSearchTextAndTagA, final DistributionSetTag dsTagA,
final String text) {
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).typeId(standardDsType.getId())
.searchText(text).tagNames(singletonList(dsTagA.getName())),
completedAndStandartTypeAndSearchTextAndTagA);
assertThatFilterDoesNotContainAnyDistributionSet(DistributionSetFilter.builder()
.typeId(standardDsType.getId()).searchText(text).tagNames(singletonList(dsTagA.getName()))
.isComplete(Boolean.FALSE).isDeleted(Boolean.FALSE));
}
private void assertThatFilterContainsOnlyGivenDistributionSets(final DistributionSetFilterBuilder filterBuilder,
final List<DistributionSet> distributionSets) {
final int expectedDsSize = distributionSets.size();
assertThat(distributionSetManagement.findByDistributionSetFilter(PAGE, filterBuilder.build()).getContent())
.hasSize(expectedDsSize).containsOnly(distributionSets.toArray(new DistributionSet[expectedDsSize]));
}
private void assertThatFilterDoesNotContainAnyDistributionSet(final DistributionSetFilterBuilder filterBuilder) {
assertThat(distributionSetManagement.findByDistributionSetFilter(PAGE, filterBuilder.build()).getContent())
.isEmpty();
}
private void assertThatFilterHasSizeAndDoesNotContainDistributionSet(
final DistributionSetFilterBuilder filterBuilder, final int size, final DistributionSet ds) {
assertThat(distributionSetManagement.findByDistributionSetFilter(PAGE, filterBuilder.build()).getContent())
.hasSize(size).doesNotContain(ds);
}
@Test
@Description("Simple DS load without the related data that should be loaded lazy.")
void findDistributionSetsWithoutLazy() {
@@ -1097,25 +803,24 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
.isEqualTo(softwareModuleCount);
}
@Autowired RepositoryProperties repositoryProperties;
@Test
@Description("Test implicit locks for a DS and skip tags.")
void isImplicitLockApplicableForDistributionSet() {
final JpaDistributionSetManagement distributionSetManagement =
(JpaDistributionSetManagement)this.distributionSetManagement;
(JpaDistributionSetManagement) this.distributionSetManagement;
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds-non-skip");
// assert that implicit lock is applicable for non skip tags
assertThat(distributionSetManagement.isImplicitLockApplicable(distributionSet)).isTrue();
assertThat(repositoryProperties.getSkipImplicitLockForTags().size()).isNotEqualTo(0);
final List<DistributionSetTag> skipTags = distributionSetTagManagement.create(
repositoryProperties.getSkipImplicitLockForTags().stream()
.map(String::toLowerCase)
// remove same in case-insensitive terms tags
// in of case-insensitive db's it will end up as same names and constraint violation (?)
.distinct()
.map(skipTag -> entityFactory.tag().create().name(skipTag))
.toList());
repositoryProperties.getSkipImplicitLockForTags().stream()
.map(String::toLowerCase)
// remove same in case-insensitive terms tags
// in of case-insensitive db's it will end up as same names and constraint violation (?)
.distinct()
.map(skipTag -> entityFactory.tag().create().name(skipTag))
.toList());
// assert that implicit lock locks for every skip tag
skipTags.forEach(skipTag -> {
DistributionSet distributionSetWithSkipTag =
@@ -1324,10 +1029,14 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
assertThat(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds3.getId())).isEmpty();
Optional<Rollout> rollout = rolloutManagement.get(rollout1.getId());
rollout.ifPresent(value -> assertThat(Rollout.RolloutStatus.valueOf(String.valueOf(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds1.getId()).get(0).getName()))).isEqualTo(value.getStatus()));
rollout.ifPresent(value -> assertThat(Rollout.RolloutStatus.valueOf(
String.valueOf(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds1.getId()).get(0).getName()))).isEqualTo(
value.getStatus()));
rollout = rolloutManagement.get(rollout2.getId());
rollout.ifPresent(value -> assertThat(Rollout.RolloutStatus.valueOf(String.valueOf(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds2.getId()).get(0).getName()))).isEqualTo(value.getStatus()));
rollout.ifPresent(value -> assertThat(Rollout.RolloutStatus.valueOf(
String.valueOf(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds2.getId()).get(0).getName()))).isEqualTo(
value.getStatus()));
}
@Test
@@ -1366,6 +1075,301 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
assertThat(distributionSetManagement.countAutoAssignmentsForDistributionSet(ds2.getId())).isNull();
}
@Step
private void createAndUpdateDistributionSetWithInvalidDescription(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long description should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version("a").description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with invalid description should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version("a").description(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long description should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with invalid characters should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateDistributionSetWithInvalidName(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long name should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().version("a")
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too short name should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name("")));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with invalid characters in name should not be created")
.isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long name should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with invalid characters should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too short name should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).name("")));
}
@Step
private void createAndUpdateDistributionSetWithInvalidVersion(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long version should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version(RandomStringUtils.randomAlphanumeric(NamedVersionedEntity.VERSION_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too short version should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("a").version("")));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too long version should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.version(RandomStringUtils.randomAlphanumeric(NamedVersionedEntity.VERSION_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("entity with too short version should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).version("")));
}
@Step
private void validateFindAll(final List<DistributionSet> expectedDistributionsets) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder(), expectedDistributionsets);
}
@Step
private void validateDeleted(final DistributionSet deletedDistributionSet, final int notDeletedSize) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isDeleted(Boolean.TRUE),
singletonList(deletedDistributionSet));
assertThatFilterHasSizeAndDoesNotContainDistributionSet(
DistributionSetFilter.builder().isDeleted(Boolean.FALSE), notDeletedSize, deletedDistributionSet);
}
@Step
private void validateCompleted(final DistributionSet dsIncomplete, final int completedSize) {
assertThatFilterHasSizeAndDoesNotContainDistributionSet(
DistributionSetFilter.builder().isComplete(Boolean.TRUE), completedSize, dsIncomplete);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.FALSE), singletonList(dsIncomplete));
}
@Step
private void validateType(final DistributionSetType newType, final DistributionSet dsNewType,
final int standardDsTypeSize) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().typeId(newType.getId()),
singletonList(dsNewType));
assertThatFilterHasSizeAndDoesNotContainDistributionSet(
DistributionSetFilter.builder().typeId(standardDsType.getId()), standardDsTypeSize, dsNewType);
}
@Step
private void validateSearchText(final List<DistributionSet> allDistributionSets, final String dsNamePrefix) {
final List<DistributionSet> withTestNamePrefix = allDistributionSets.stream()
.filter(ds -> ds.getName().startsWith(dsNamePrefix)).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(dsNamePrefix),
withTestNamePrefix);
final List<DistributionSet> withTestNameExact = withTestNamePrefix.stream()
.filter(ds -> ds.getName().equals(dsNamePrefix)).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().searchText(dsNamePrefix + ":"), withTestNameExact);
final List<DistributionSet> withTestNameExactAndVersionPrefix = withTestNameExact.stream()
.filter(ds -> ds.getVersion().startsWith("1")).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().searchText(dsNamePrefix + ":1"),
withTestNameExactAndVersionPrefix);
final List<DistributionSet> dsWithExactNameAndVersion = withTestNameExactAndVersionPrefix.stream()
.filter(ds -> ds.getVersion().equals("1.0.0")).collect(Collectors.toList());
assertThat(dsWithExactNameAndVersion).hasSize(1);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().searchText(dsNamePrefix + ":1.0.0"), dsWithExactNameAndVersion);
final List<DistributionSet> withVersionPrefix = allDistributionSets.stream()
.filter(ds -> ds.getVersion().startsWith("1.0.")).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":1.0."),
withVersionPrefix);
final List<DistributionSet> withVersionExact = withVersionPrefix.stream()
.filter(ds -> ds.getVersion().equals("1.0.0")).collect(Collectors.toList());
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":1.0.0"),
withVersionExact);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(":"),
allDistributionSets);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().searchText(" : "),
allDistributionSets);
}
@Step
private void validateTags(final DistributionSetTag dsTagA, final DistributionSetTag dsTagB,
final DistributionSetTag dsTagC, final List<DistributionSet> dsWithTagA,
final List<DistributionSet> dsWithTagB) {
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().tagNames(singletonList(dsTagA.getName())), dsWithTagA);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().tagNames(singletonList(dsTagB.getName())), dsWithTagB);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().tagNames(Arrays.asList(dsTagA.getName(), dsTagB.getName())),
dsWithTagA);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().tagNames(Arrays.asList(dsTagC.getName(), dsTagB.getName())),
dsWithTagB);
assertThatFilterDoesNotContainAnyDistributionSet(
DistributionSetFilter.builder().tagNames(singletonList(dsTagC.getName())));
}
@Step
private void validateDeletedAndCompleted(final List<DistributionSet> completedStandardType,
final DistributionSet dsNewType, final DistributionSet dsDeleted) {
final List<DistributionSet> completedNotDeleted = new ArrayList<>(completedStandardType);
completedNotDeleted.add(dsNewType);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).isDeleted(Boolean.FALSE),
completedNotDeleted);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).isDeleted(Boolean.TRUE),
singletonList(dsDeleted));
assertThatFilterDoesNotContainAnyDistributionSet(
DistributionSetFilter.builder().isComplete(Boolean.FALSE).isDeleted(Boolean.TRUE));
}
@Step
private void validateDeletedAndCompletedAndType(final List<DistributionSet> deletedAndCompletedAndStandardType,
final DistributionSet dsDeleted, final DistributionSetType newType, final DistributionSet dsNewType) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isDeleted(Boolean.FALSE)
.isComplete(Boolean.TRUE).typeId(standardDsType.getId()), deletedAndCompletedAndStandardType);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isComplete(Boolean.TRUE)
.typeId(standardDsType.getId()).isDeleted(Boolean.TRUE), singletonList(dsDeleted));
assertThatFilterDoesNotContainAnyDistributionSet(DistributionSetFilter.builder().isDeleted(Boolean.TRUE)
.isComplete(Boolean.FALSE).typeId(standardDsType.getId()));
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).typeId(newType.getId()),
singletonList(dsNewType));
}
@Step
private void validateDeletedAndCompletedAndTypeAndSearchText(
final List<DistributionSet> completedAndStandardTypeAndSearchText, final DistributionSetType newType,
final String text) {
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isDeleted(Boolean.FALSE)
.isComplete(Boolean.TRUE).typeId(standardDsType.getId()).searchText(text),
completedAndStandardTypeAndSearchText);
assertThatFilterDoesNotContainAnyDistributionSet(DistributionSetFilter.builder().isComplete(Boolean.TRUE)
.isDeleted(Boolean.TRUE).typeId(standardDsType.getId()).searchText(text + ":"));
assertThatFilterDoesNotContainAnyDistributionSet(
DistributionSetFilter.builder().typeId(standardDsType.getId()).searchText(text)
.isComplete(Boolean.FALSE).isDeleted(Boolean.FALSE));
assertThatFilterDoesNotContainAnyDistributionSet(DistributionSetFilter.builder().typeId(newType.getId())
.searchText(text).isComplete(Boolean.TRUE).isDeleted(Boolean.FALSE));
}
@Step
private void validateDeletedAndCompletedAndTypeAndSearchText(
final List<DistributionSet> completedAndNotDeletedStandardTypeAndFilterString,
final DistributionSet dsDeleted, final DistributionSet dsInComplete, final DistributionSet dsNewType,
final DistributionSetType newType, final String filterString) {
final List<DistributionSet> completedAndStandardTypeAndFilterString = new ArrayList<>(
completedAndNotDeletedStandardTypeAndFilterString);
completedAndStandardTypeAndFilterString.add(dsDeleted);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isComplete(Boolean.TRUE)
.typeId(standardDsType.getId()).searchText(filterString),
completedAndStandardTypeAndFilterString);
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).isDeleted(Boolean.FALSE)
.typeId(standardDsType.getId()).searchText(filterString),
completedAndNotDeletedStandardTypeAndFilterString);
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().isComplete(Boolean.TRUE)
.isDeleted(Boolean.TRUE).typeId(standardDsType.getId()).searchText(filterString),
singletonList(dsDeleted));
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().typeId(standardDsType.getId()).searchText(filterString)
.isComplete(Boolean.FALSE).isDeleted(Boolean.FALSE),
singletonList(dsInComplete));
assertThatFilterContainsOnlyGivenDistributionSets(DistributionSetFilter.builder().typeId(newType.getId())
.searchText(filterString).isComplete(Boolean.TRUE).isDeleted(Boolean.FALSE),
singletonList(dsNewType));
}
@Step
private void validateDeletedAndCompletedAndTypeAndSearchTextAndTag(
final List<DistributionSet> completedAndStandartTypeAndSearchTextAndTagA, final DistributionSetTag dsTagA,
final String text) {
assertThatFilterContainsOnlyGivenDistributionSets(
DistributionSetFilter.builder().isComplete(Boolean.TRUE).typeId(standardDsType.getId())
.searchText(text).tagNames(singletonList(dsTagA.getName())),
completedAndStandartTypeAndSearchTextAndTagA);
assertThatFilterDoesNotContainAnyDistributionSet(DistributionSetFilter.builder()
.typeId(standardDsType.getId()).searchText(text).tagNames(singletonList(dsTagA.getName()))
.isComplete(Boolean.FALSE).isDeleted(Boolean.FALSE));
}
private void assertThatFilterContainsOnlyGivenDistributionSets(final DistributionSetFilterBuilder filterBuilder,
final List<DistributionSet> distributionSets) {
final int expectedDsSize = distributionSets.size();
assertThat(distributionSetManagement.findByDistributionSetFilter(PAGE, filterBuilder.build()).getContent())
.hasSize(expectedDsSize).containsOnly(distributionSets.toArray(new DistributionSet[expectedDsSize]));
}
private void assertThatFilterDoesNotContainAnyDistributionSet(final DistributionSetFilterBuilder filterBuilder) {
assertThat(distributionSetManagement.findByDistributionSetFilter(PAGE, filterBuilder.build()).getContent())
.isEmpty();
}
private void assertThatFilterHasSizeAndDoesNotContainDistributionSet(
final DistributionSetFilterBuilder filterBuilder, final int size, final DistributionSet ds) {
assertThat(distributionSetManagement.findByDistributionSetFilter(PAGE, filterBuilder.build()).getContent())
.hasSize(size).doesNotContain(ds);
}
// can be removed with java-11
private <T> T getOrThrow(final Optional<T> opt) {
return opt.orElseThrow(NoSuchElementException::new);

View File

@@ -22,6 +22,10 @@ import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.builder.TagCreate;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
@@ -33,17 +37,10 @@ import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetFilter;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.springframework.data.domain.Pageable;
/**
@@ -53,6 +50,8 @@ import org.springframework.data.domain.Pageable;
@Story("DistributionSet Tag Management")
public class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest {
private static final Random RND = new Random();
@Test
@Description("Verifies that management get access reacts as specfied on calls for non existing entities by means "
+ "of Optional not present.")
@@ -137,17 +136,6 @@ public class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest
Stream.of(dsCs, dsACs, dsBCs, dsABCs));
}
@Step
private void verifyExpectedFilteredDistributionSets(final DistributionSetFilter.DistributionSetFilterBuilder distributionSetFilterBuilder,
final Stream<Collection<DistributionSet>> expectedFilteredDistributionSets) {
final Collection<Long> retrievedFilteredDsIds = distributionSetManagement
.findByDistributionSetFilter(PAGE, distributionSetFilterBuilder.build()).stream()
.map(DistributionSet::getId).collect(Collectors.toList());
final Collection<Long> expectedFilteredDsIds = expectedFilteredDistributionSets.flatMap(Collection::stream)
.map(DistributionSet::getId).collect(Collectors.toList());
assertThat(retrievedFilteredDsIds).hasSameElementsAs(expectedFilteredDsIds);
}
@Test
@Description("Verifies assign/unassign.")
public void assignAndUnassignDistributionSetTags() {
@@ -162,7 +150,9 @@ public class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest
assertThat(result).size().isEqualTo(20);
assertThat(result).containsAll(distributionSetManagement
.get(groupA.stream().map(DistributionSet::getId).collect(Collectors.toList())));
assertThat(distributionSetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent().stream().map(DistributionSet::getId).sorted().toList())
assertThat(
distributionSetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent().stream().map(DistributionSet::getId).sorted()
.toList())
.isEqualTo(groupA.stream().map(DistributionSet::getId).sorted().toList());
final Collection<DistributionSet> groupAB = concat(groupA, groupB);
@@ -171,7 +161,9 @@ public class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest
assertThat(result).size().isEqualTo(40);
assertThat(result).containsAll(distributionSetManagement
.get(groupAB.stream().map(DistributionSet::getId).collect(Collectors.toList())));
assertThat(distributionSetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent().stream().map(DistributionSet::getId).sorted().toList())
assertThat(
distributionSetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent().stream().map(DistributionSet::getId).sorted()
.toList())
.isEqualTo(groupAB.stream().map(DistributionSet::getId).sorted().toList());
// toggle A+B -> both unassigned
@@ -182,7 +174,6 @@ public class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest
assertThat(distributionSetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent()).isEmpty();
}
private static final Random RND = new Random();
@Test
@Description("Verifies that tagging of set containing missing DS throws meaningful and correct exception.")
public void failOnMissingDs() {
@@ -312,6 +303,17 @@ public class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest
assertThat(distributionSetTagRepository.findAll()).as("Wrong size of tags created").hasSize(tags.size());
}
@Step
private void verifyExpectedFilteredDistributionSets(final DistributionSetFilter.DistributionSetFilterBuilder distributionSetFilterBuilder,
final Stream<Collection<DistributionSet>> expectedFilteredDistributionSets) {
final Collection<Long> retrievedFilteredDsIds = distributionSetManagement
.findByDistributionSetFilter(PAGE, distributionSetFilterBuilder.build()).stream()
.map(DistributionSet::getId).collect(Collectors.toList());
final Collection<Long> expectedFilteredDsIds = expectedFilteredDistributionSets.flatMap(Collection::stream)
.map(DistributionSet::getId).collect(Collectors.toList());
assertThat(retrievedFilteredDsIds).hasSameElementsAs(expectedFilteredDsIds);
}
private List<DistributionSetTag> createDsSetsWithTags() {
final Collection<DistributionSet> sets = testdataFactory.createDistributionSets(20);
final Iterable<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(20);

View File

@@ -21,8 +21,11 @@ import java.util.Set;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.assertj.core.util.Lists;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
@@ -42,18 +45,13 @@ import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
/**
* {@link DistributionSetManagement} tests.
*
*/
@Feature("Component Tests - Repository")
@Story("DistributionSet Management")
public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Verifies that management get access react as specfied on calls for non existing entities by means "
+ "of Optional not present.")
@@ -77,13 +75,13 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
softwareModuleTypes), "DistributionSetType");
final List<Long> notExistingSwModuleTypeIds = Collections.singletonList(NOT_EXIST_IDL);
verifyThrownExceptionBy(() -> distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(
testdataFactory.findOrCreateDistributionSetType("xxx", "xxx").getId(), notExistingSwModuleTypeIds),
testdataFactory.findOrCreateDistributionSetType("xxx", "xxx").getId(), notExistingSwModuleTypeIds),
"SoftwareModuleType");
verifyThrownExceptionBy(() -> distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(NOT_EXIST_IDL,
softwareModuleTypes), "DistributionSetType");
verifyThrownExceptionBy(() -> distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(
testdataFactory.findOrCreateDistributionSetType("xxx", "xxx").getId(), notExistingSwModuleTypeIds),
testdataFactory.findOrCreateDistributionSetType("xxx", "xxx").getId(), notExistingSwModuleTypeIds),
"SoftwareModuleType");
verifyThrownExceptionBy(() -> distributionSetTypeManagement.delete(NOT_EXIST_IDL), "DistributionSetType");
@@ -106,96 +104,6 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
createAndUpdateDistributionSetWithInvalidVersion(set);
}
@Step
private void createAndUpdateDistributionSetWithInvalidDescription(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too long description should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version("a").description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set invalid description text should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version("a").description(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too long description should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with invalid description should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateDistributionSetWithInvalidName(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class).as("set with too long name should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().version("a")
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with invalid name should not be created")
.isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too short name should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name("")));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with null name should not be created")
.isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name(null)));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with too long name should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with invalid name should not be updated")
.isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too short name should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).name("")));
}
@Step
private void createAndUpdateDistributionSetWithInvalidVersion(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too long version should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version(RandomStringUtils.randomAlphanumeric(NamedVersionedEntity.VERSION_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with invalid version should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("a").version(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too short version should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("a").version("")));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with null version should not be created")
.isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("a").version(null)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too long version should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.version(RandomStringUtils.randomAlphanumeric(NamedVersionedEntity.VERSION_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with invalid version should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).version(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too short version should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).version("")));
}
@Test
@Description("Tests the successful module update of unused distribution set type which is in fact allowed.")
public void updateUnassignedDistributionSetTypeModules() {
@@ -290,16 +198,7 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
assertThatThrownBy(() -> distributionSetTypeManagement
.assignMandatorySoftwareModuleTypes(nonUpdatableType.getId(), Set.of(osType.getId())))
.isInstanceOf(EntityReadOnlyException.class);
}
private DistributionSetType createDistributionSetTypeUsedByDs() {
final DistributionSetType nonUpdatableType = distributionSetTypeManagement.create(entityFactory
.distributionSetType().create().key("updatableType").name("to be deleted").colour("test123"));
assertThat(distributionSetTypeManagement.getByKey("updatableType").get().getMandatoryModuleTypes()).isEmpty();
distributionSetManagement.create(entityFactory.distributionSet().create().name("newtypesoft").version("1")
.type(nonUpdatableType.getKey()));
return nonUpdatableType;
.isInstanceOf(EntityReadOnlyException.class);
}
@Test
@@ -365,4 +264,103 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
assertThat(jpaDistributionSetType.checkComplete(distributionSet)).isFalse();
}
@Step
private void createAndUpdateDistributionSetWithInvalidDescription(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too long description should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version("a").description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set invalid description text should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version("a").description(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too long description should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with invalid description should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateDistributionSetWithInvalidName(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class).as("set with too long name should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().version("a")
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with invalid name should not be created")
.isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too short name should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name("")));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with null name should not be created")
.isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().version("a").name(null)));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with too long name should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with invalid name should not be updated")
.isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too short name should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).name("")));
}
@Step
private void createAndUpdateDistributionSetWithInvalidVersion(final DistributionSet set) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too long version should not be created")
.isThrownBy(() -> distributionSetManagement.create(entityFactory.distributionSet().create().name("a")
.version(RandomStringUtils.randomAlphanumeric(NamedVersionedEntity.VERSION_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with invalid version should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("a").version(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too short version should not be created").isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("a").version("")));
assertThatExceptionOfType(ConstraintViolationException.class).as("set with null version should not be created")
.isThrownBy(() -> distributionSetManagement
.create(entityFactory.distributionSet().create().name("a").version(null)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too long version should not be updated")
.isThrownBy(() -> distributionSetManagement.update(entityFactory.distributionSet().update(set.getId())
.version(RandomStringUtils.randomAlphanumeric(NamedVersionedEntity.VERSION_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with invalid version should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).version(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set with too short version should not be updated").isThrownBy(() -> distributionSetManagement
.update(entityFactory.distributionSet().update(set.getId()).version("")));
}
private DistributionSetType createDistributionSetTypeUsedByDs() {
final DistributionSetType nonUpdatableType = distributionSetTypeManagement.create(entityFactory
.distributionSetType().create().key("updatableType").name("to be deleted").colour("test123"));
assertThat(distributionSetTypeManagement.getByKey("updatableType").get().getMandatoryModuleTypes()).isEmpty();
distributionSetManagement.create(entityFactory.distributionSet().create().name("newtypesoft").version("1")
.type(nonUpdatableType.getKey()));
return nonUpdatableType;
}
}

View File

@@ -13,6 +13,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.TimeUnit;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
@@ -24,10 +27,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestPropertySource;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Controller Management")
@TestPropertySource(locations = "classpath:/jpa-test.properties", properties = {

View File

@@ -13,6 +13,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
@@ -38,10 +41,6 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.util.CollectionUtils;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Rollout Management")
class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
@@ -159,42 +158,11 @@ class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
.hasSize((int) rolloutGroupManagement.countTargetsOfRolloutsGroup(rolloutGroup.getId()));
targetsWithActionStatus = rolloutGroupManagement.findAllTargetsOfRolloutGroupWithActionStatus(
PageRequest.of(0, 500, Sort.by(Direction.DESC, "lastActionStatusCode")), rolloutGroup.getId())
PageRequest.of(0, 500, Sort.by(Direction.DESC, "lastActionStatusCode")), rolloutGroup.getId())
.getContent();
assertSortedListOfActionStatus(targetsWithActionStatus, target24, 24, target0, 0);
}
private void assertSortedListOfActionStatus(final List<TargetWithActionStatus> targetsWithActionStatus,
final Target first, final Integer firstStatusCode, final Target last, final Integer lastStatusCode) {
assertTargetAndActionStatusCode(CollectionUtils.firstElement(targetsWithActionStatus), first, firstStatusCode);
assertTargetAndActionStatusCode(CollectionUtils.lastElement(targetsWithActionStatus), last, lastStatusCode);
}
private void assertTargetAndActionStatusCode(final TargetWithActionStatus targetWithActionStatus,
final Target target, final Integer actionStatusCode) {
assertThat(targetWithActionStatus.getTarget().getControllerId()).isEqualTo(target.getControllerId());
assertThat(targetWithActionStatus.getLastActionStatusCode()).isEqualTo(actionStatusCode);
}
private void assertTargetNotNullAndActionStatusNullAndActionStatusCode(
final List<TargetWithActionStatus> targetsWithActionStatus, final Integer actionStatusCode) {
targetsWithActionStatus.forEach(targetWithActionStatus -> {
assertThat(targetWithActionStatus.getTarget().getControllerId()).isNotNull();
assertThat(targetWithActionStatus.getStatus()).isNull();
assertThat(targetWithActionStatus.getLastActionStatusCode()).isEqualTo(actionStatusCode);
});
}
private void assertTargetNotNullAndActionStatusAndActionStatusCode(
final List<TargetWithActionStatus> targetsWithActionStatus, final Status actionStatus,
final Integer actionStatusCode) {
targetsWithActionStatus.forEach(targetWithActionStatus -> {
assertThat(targetWithActionStatus.getTarget().getControllerId()).isNotNull();
assertThat(targetWithActionStatus.getStatus()).isEqualTo(actionStatus);
assertThat(targetWithActionStatus.getLastActionStatusCode()).isEqualTo(actionStatusCode);
});
}
@Test
@Description("Verifies that Rollouts in different states are handled correctly.")
void findAllTargetsOfRolloutGroupWithActionStatus() {
@@ -249,6 +217,37 @@ class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
Status.RUNNING, 100);
}
private void assertSortedListOfActionStatus(final List<TargetWithActionStatus> targetsWithActionStatus,
final Target first, final Integer firstStatusCode, final Target last, final Integer lastStatusCode) {
assertTargetAndActionStatusCode(CollectionUtils.firstElement(targetsWithActionStatus), first, firstStatusCode);
assertTargetAndActionStatusCode(CollectionUtils.lastElement(targetsWithActionStatus), last, lastStatusCode);
}
private void assertTargetAndActionStatusCode(final TargetWithActionStatus targetWithActionStatus,
final Target target, final Integer actionStatusCode) {
assertThat(targetWithActionStatus.getTarget().getControllerId()).isEqualTo(target.getControllerId());
assertThat(targetWithActionStatus.getLastActionStatusCode()).isEqualTo(actionStatusCode);
}
private void assertTargetNotNullAndActionStatusNullAndActionStatusCode(
final List<TargetWithActionStatus> targetsWithActionStatus, final Integer actionStatusCode) {
targetsWithActionStatus.forEach(targetWithActionStatus -> {
assertThat(targetWithActionStatus.getTarget().getControllerId()).isNotNull();
assertThat(targetWithActionStatus.getStatus()).isNull();
assertThat(targetWithActionStatus.getLastActionStatusCode()).isEqualTo(actionStatusCode);
});
}
private void assertTargetNotNullAndActionStatusAndActionStatusCode(
final List<TargetWithActionStatus> targetsWithActionStatus, final Status actionStatus,
final Integer actionStatusCode) {
targetsWithActionStatus.forEach(targetWithActionStatus -> {
assertThat(targetWithActionStatus.getTarget().getControllerId()).isNotNull();
assertThat(targetWithActionStatus.getStatus()).isEqualTo(actionStatus);
assertThat(targetWithActionStatus.getLastActionStatusCode()).isEqualTo(actionStatusCode);
});
}
private void assertThatListIsSortedByTargetName(final List<TargetWithActionStatus> targets,
final Direction sortDirection) {
String previousName = null;

View File

@@ -9,6 +9,11 @@
*/
package org.eclipse.hawkbit.repository.jpa.management;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@@ -24,17 +29,10 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.test.context.TestPropertySource;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Junit tests for RolloutManagement.
*/
@@ -300,7 +298,6 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
assertGroup(dynamic2, true, RolloutGroupStatus.RUNNING, 4); // assign the target created when paused
}
@Test
@Description("Verifies a simple pure (no static groups) dynamic rollout flow with a dynamic group template")
void dynamicRolloutPureFlow() {
@@ -362,7 +359,7 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
assertAndGetRunning(rollout, 1); // remains on in the first dynamic
rolloutHandler.handleAll();
assertRollout(rollout, true, RolloutStatus.RUNNING, 2, 8);
assertRollout(rollout, true, RolloutStatus.RUNNING, 2, 8);
assertGroup(dynamic1, true, RolloutGroupStatus.RUNNING, 6);
// first dynamic threshold is reached, second is started
assertGroup(dynamic2, true, RolloutGroupStatus.RUNNING, 2);

View File

@@ -29,6 +29,10 @@ import java.util.stream.Stream;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.ValidationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.Condition;
@@ -96,11 +100,6 @@ import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
/**
* Junit tests for RolloutManagement.
*/
@@ -108,6 +107,68 @@ import io.qameta.allure.Story;
@Story("Rollout Management")
class RolloutManagementTest extends AbstractJpaIntegrationTest {
/**
* Tests static assignment aspects of the dynamic group assignment filters.
*/
@Test
@Description("Dynamic group doesn't override newer static group assignments")
public void dynamicGroupDoesntOverrideItsOrNewerStaticGroups() {
final int amountGroups = 1; // static only
final String targetPrefix = "controller-dynamic-rollout-";
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds");
testdataFactory.createTargets(targetPrefix, 0, amountGroups * 2);
final Rollout dynamicRollout = testdataFactory.createRolloutByVariables("dynamic", "static rollout", amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "0", "30", ActionType.FORCED, 1000, false, true);
rolloutManagement.start(dynamicRollout.getId());
rolloutHandler.handleAll();
assertRollout(dynamicRollout, true, RolloutStatus.RUNNING, amountGroups + 1, amountGroups * 2);
final List<RolloutGroup> dynamicGroups = rolloutGroupManagement.findByRollout(
new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id")),
dynamicRollout.getId()).getContent();
for (int i = 0; i < dynamicGroups.size(); i++) {
final RolloutGroup group = dynamicGroups.get(i);
if (i + 1 == dynamicGroups.size()) {
assertGroup(group, true, RolloutGroupStatus.SCHEDULED, 0);
} else {
assertGroup(group, false, RolloutGroupStatus.RUNNING, 2);
}
}
assertAndGetRunning(dynamicRollout, 2).forEach(this::finishAction);
rolloutHandler.handleAll();
for (int i = 0; i < dynamicGroups.size(); i++) {
final RolloutGroup group = dynamicGroups.get(i);
if (i + 1 == dynamicGroups.size()) {
assertGroup(group, true, RolloutGroupStatus.RUNNING, 0);
} else {
assertGroup(group, false, RolloutGroupStatus.FINISHED, 2);
}
}
assertAndGetRunning(dynamicRollout, 0);
rolloutHandler.handleAll();
// NB: asserts that dynamic group doesn't get from its static groups (already finished action targets)
assertGroup(dynamicGroups.get(dynamicGroups.size() - 1), true, RolloutGroupStatus.RUNNING, 0);
assertAndGetRunning(dynamicRollout, 0);
rolloutManagement.pauseRollout(dynamicRollout.getId());
rolloutHandler.handleAll();
testdataFactory.createTargets(targetPrefix, amountGroups * 2, amountGroups);
final Rollout staticRollout = testdataFactory.createRolloutByVariables("static", "static rollout", amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "0", "30", ActionType.FORCED, 0, false, false);
rolloutManagement.start(staticRollout.getId());
rolloutHandler.handleAll();
assertRollout(staticRollout, false, RolloutStatus.RUNNING, amountGroups, amountGroups * 3);
final List<RolloutGroup> staticGroups = rolloutGroupManagement.findByRollout(
new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id")),
staticRollout.getId()).getContent();
staticGroups.forEach(group -> assertGroup(group, false, RolloutGroupStatus.RUNNING, 3));
rolloutManagement.resumeRollout(dynamicRollout.getId());
rolloutHandler.handleAll(); // resume, do not get last devices (they are assigned to a newer group, nevertheless newer is with bigger weight
assertGroup(dynamicGroups.get(dynamicGroups.size() - 1), true, RolloutGroupStatus.RUNNING, 0);
assertAndGetRunning(dynamicRollout, 0);
}
@BeforeEach
void reset() {
this.approvalStrategy.setApprovalNeeded(false);
@@ -176,13 +237,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(actionsByKnownTarget.get(0).getStatus()).isEqualTo(expectedStatus);
}
private static Stream<Arguments> simpleRolloutsPossibilities() {
return Stream.of(Arguments.of(true, true, Status.WAIT_FOR_CONFIRMATION), //
Arguments.of(true, false, Status.RUNNING), //
Arguments.of(false, true, Status.RUNNING), //
Arguments.of(false, false, Status.RUNNING));//
}
@Test
@Description("Verifies that a running action is auto canceled by a rollout which assigns another distribution-set.")
void rolloutAssignsNewDistributionSetAndAutoCloseActiveActions() {
@@ -382,64 +436,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
verifyRolloutAndAllGroupsAreFinished(createdRollout);
}
@Step("Finish three actions of the rollout group and delete two targets")
private void finishActionAndDeleteTargetsOfFirstRunningGroup(final Rollout createdRollout) {
// finish group one by finishing targets and deleting targets
final Slice<JpaAction> runningActionsSlice = actionRepository.findByRolloutIdAndStatus(PAGE,
createdRollout.getId(), Status.RUNNING);
final List<JpaAction> runningActions = runningActionsSlice.getContent();
finishAction(runningActions.get(0));
finishAction(runningActions.get(1));
finishAction(runningActions.get(2));
targetManagement.delete(
Arrays.asList(runningActions.get(3).getTarget().getId(), runningActions.get(4).getTarget().getId()));
}
@Step("Check the status of the rollout groups, second group should be in running status")
private void checkSecondGroupStatusIsRunning(final Rollout createdRollout) {
rolloutHandler.handleAll();
final List<RolloutGroup> runningRolloutGroups = rolloutGroupManagement
.findByRollout(new OffsetBasedPageRequest(0, 10, Sort.by(Direction.ASC, "id")), createdRollout.getId())
.getContent();
assertThat(runningRolloutGroups.get(0).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
assertThat(runningRolloutGroups.get(1).getStatus()).isEqualTo(RolloutGroupStatus.RUNNING);
assertThat(runningRolloutGroups.get(2).getStatus()).isEqualTo(RolloutGroupStatus.SCHEDULED);
}
@Step("Finish one action of the rollout group and delete four targets")
private void finishActionAndDeleteTargetsOfSecondRunningGroup(final Rollout createdRollout) {
final Slice<JpaAction> runningActionsSlice = actionRepository.findByRolloutIdAndStatus(PAGE,
createdRollout.getId(), Status.RUNNING);
final List<JpaAction> runningActions = runningActionsSlice.getContent();
finishAction(runningActions.get(0));
targetManagement.delete(
Arrays.asList(runningActions.get(1).getTarget().getId(), runningActions.get(2).getTarget().getId(),
runningActions.get(3).getTarget().getId(), runningActions.get(4).getTarget().getId()));
}
@Step("Delete all targets of the rollout group")
private void deleteAllTargetsFromThirdGroup(final Rollout createdRollout) {
final Slice<JpaAction> runningActionsSlice = actionRepository.findByRolloutIdAndStatus(PAGE,
createdRollout.getId(), Status.SCHEDULED);
final List<JpaAction> runningActions = runningActionsSlice.getContent();
targetManagement.delete(Arrays.asList(runningActions.get(0).getTarget().getId(),
runningActions.get(1).getTarget().getId(), runningActions.get(2).getTarget().getId(),
runningActions.get(3).getTarget().getId(), runningActions.get(4).getTarget().getId()));
}
@Step("Check the status of the rollout groups and the rollout")
private void verifyRolloutAndAllGroupsAreFinished(final Rollout createdRollout) {
rolloutHandler.handleAll();
final List<RolloutGroup> runningRolloutGroups = rolloutGroupManagement
.findByRollout(PAGE, createdRollout.getId()).getContent();
assertThat(runningRolloutGroups.get(0).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
assertThat(runningRolloutGroups.get(1).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
assertThat(runningRolloutGroups.get(2).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
assertThat(reloadRollout(createdRollout).getStatus()).isEqualTo(RolloutStatus.FINISHED);
}
@Test
@Description("Verifying that the error handling action of a group is executed to pause the current rollout")
void checkErrorHitOfGroupCallsErrorActionToPauseTheRollout() {
@@ -1491,14 +1487,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(myRollout.getDescription()).isEqualTo("newDesc");
}
private Rollout reloadRollout(final Rollout r) {
return getRollout(r.getId());
}
private Rollout getRollout(final Long myRolloutId) {
return rolloutManagement.get(myRolloutId).orElseThrow(NoSuchElementException::new);
}
@Test
@Description("Verify the creation of a rollout with a groups definition.")
void createRolloutWithGroupDefinition() throws Exception {
@@ -1635,41 +1623,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
}
private void assertRolloutGroup(final long rolloutGroupId, final RolloutGroupStatus status,
final boolean isConfirmationRequired, final long totalTargets, final Status actionStatusToCheck) {
assertThat(rolloutGroupManagement.get(rolloutGroupId)).hasValueSatisfying(rolloutGroup -> {
assertThat(rolloutGroup.getStatus()).isEqualTo(status);
assertThat(rolloutGroup.isConfirmationRequired()).isEqualTo(isConfirmationRequired);
assertThat(rolloutGroup.getTotalTargets()).isEqualTo(totalTargets);
if (actionStatusToCheck != null) {
assertAllActionOfRolloutGroupHavingStatus(rolloutGroup.getId(), actionStatusToCheck);
}
});
}
private void assertAllActionOfRolloutGroupHavingStatus(final long rolloutGroupId, final Status status) {
final List<Target> targets = rolloutGroupManagement.findTargetsOfRolloutGroup(PAGE, rolloutGroupId)
.getContent();
targets.forEach(target -> {
final List<Action> activeActions = deploymentManagement
.findActionsByTarget(target.getControllerId(), PAGE).getContent();
assertThat(activeActions).hasSize(1);
assertThat(activeActions.get(0).getStatus()).isEqualTo(status);
});
}
private void forceQuitAllActionsOfRolloutGroup(final long rolloutGroupId) {
final List<Target> targets = rolloutGroupManagement.findTargetsOfRolloutGroup(PAGE, rolloutGroupId)
.getContent();
targets.forEach(target -> {
deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()).getContent().stream().map(Identifiable::getId)
.forEach(actionId -> {
deploymentManagement.cancelAction(actionId);
deploymentManagement.forceQuitAction(actionId);
});
});
}
@Test
@Description("Verify rollout creation fails if group definition does not address all targets")
void createRolloutWithGroupsNotMatchingTargets() {
@@ -1961,8 +1914,8 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
@Description("Creating a rollout with a weight causes an error when multi assignment in disabled.")
void weightAllowedWhenMultiAssignmentModeNotEnabled() {
testdataFactory.createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10, 2, "50",
"80",
ActionType.FORCED, 66);
"80",
ActionType.FORCED, 66);
}
@Test
@@ -1996,7 +1949,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
enableMultiAssignments();
final Long rolloutId = testdataFactory
.createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2, amountOfTargets,
"80", "50", null, weight).getId();
"80", "50", null, weight).getId();
rolloutManagement.start(rolloutId);
rolloutHandler.handleAll();
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
@@ -2086,102 +2039,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.doesNotContainAnyElementsOf(incompatibleTargets);
}
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage,
final String targetFilter) {
return generateRolloutGroup(index, percentage, targetFilter, false);
}
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage,
final String targetFilter, final boolean confirmationRequired) {
return entityFactory.rolloutGroup().create().name("Group" + index).description("Group" + index + "desc")
.targetPercentage(Float.valueOf(percentage)).targetFilterQuery(targetFilter)
.confirmationRequired(confirmationRequired);
}
private RolloutCreate generateTargetsAndRollout(final String rolloutName, final int amountTargetsForRollout) {
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
testdataFactory.createTargets(amountTargetsForRollout, rolloutName + "-", rolloutName);
return entityFactory.rollout().create().name(rolloutName)
.description("This is a test description for the rollout")
.targetFilterQuery("controllerId==" + rolloutName + "-*").distributionSetId(distributionSet);
}
private void validateRolloutGroupActionStatus(final RolloutGroup rolloutGroup,
final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus) {
final RolloutGroup rolloutGroupWithDetail = rolloutGroupManagement.getWithDetailedStatus(rolloutGroup.getId())
.get();
validateStatus(rolloutGroupWithDetail.getTotalTargetCountStatus(), expectedTargetCountStatus);
}
private void validateRolloutActionStatus(final Long rolloutId,
final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus) {
final Rollout rolloutWithDetail = rolloutManagement.getWithDetailedStatus(rolloutId).get();
validateStatus(rolloutWithDetail.getTotalTargetCountStatus(), expectedTargetCountStatus);
}
private void validateStatus(final TotalTargetCountStatus totalTargetCountStatus,
final Map<TotalTargetCountStatus.Status, Long> expectedTotalCountStates) {
for (final Map.Entry<TotalTargetCountStatus.Status, Long> entry : expectedTotalCountStates.entrySet()) {
final Long countReady = totalTargetCountStatus.getTotalTargetCountByStatus(entry.getKey());
assertThat(countReady).as("targets in status " + entry.getKey()).isEqualTo(entry.getValue());
}
}
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
final String targetPrefixName) {
return createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout, groupSize, successCondition,
errorCondition, rolloutName, targetPrefixName, null);
}
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
final String targetPrefixName, final Integer weight) {
final DistributionSet dsForRolloutTwo = testdataFactory.createDistributionSet("dsFor" + rolloutName);
testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName);
return testdataFactory.createRolloutByVariables(rolloutName, rolloutName + "description", groupSize,
"controllerId==" + targetPrefixName + "-*", dsForRolloutTwo, successCondition, errorCondition,
Action.ActionType.FORCED, weight, false);
}
private int changeStatusForAllRunningActions(final Rollout rollout, final Status status) {
final List<Action> runningActions = findActionsByRolloutAndStatus(rollout, Status.RUNNING);
for (final Action action : runningActions) {
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(status));
}
return runningActions.size();
}
private int changeStatusForRunningActions(final Rollout rollout, final Status status,
final int amountOfTargetsToGetChanged) {
final List<Action> runningActions = findActionsByRolloutAndStatus(rollout, Status.RUNNING);
assertThat(runningActions.size()).isGreaterThanOrEqualTo(amountOfTargetsToGetChanged);
for (int i = 0; i < amountOfTargetsToGetChanged; i++) {
controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(runningActions.get(i).getId()).status(status));
}
return runningActions.size();
}
private static Map<TotalTargetCountStatus.Status, Long> createInitStatusMap() {
final Map<TotalTargetCountStatus.Status, Long> map = new HashMap<>();
for (final TotalTargetCountStatus.Status status : TotalTargetCountStatus.Status.values()) {
map.put(status, 0L);
}
return map;
}
private void awaitRunningState(final Long myRolloutId) {
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofMillis(500)).with()
.until(() -> SecurityContextSwitch
.runAsPrivileged(
() -> rolloutManagement.get(myRolloutId).orElseThrow(NoSuchElementException::new))
.getStatus().equals(RolloutStatus.RUNNING));
}
@Test
@Description("Verifying that next group is started on manual trigger next group.")
void checkRunningRolloutsManualTriggerNextGroup() {
@@ -2272,65 +2129,207 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.withMessageContaining(errorMessage);
}
/**
* Tests static assignment aspects of the dynamic group assignment filters.
*/
@Test
@Description("Dynamic group doesn't override newer static group assignments")
public void dynamicGroupDoesntOverrideItsOrNewerStaticGroups() {
final int amountGroups = 1; // static only
final String targetPrefix = "controller-dynamic-rollout-";
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds");
private static Stream<Arguments> simpleRolloutsPossibilities() {
return Stream.of(Arguments.of(true, true, Status.WAIT_FOR_CONFIRMATION), //
Arguments.of(true, false, Status.RUNNING), //
Arguments.of(false, true, Status.RUNNING), //
Arguments.of(false, false, Status.RUNNING));//
}
testdataFactory.createTargets(targetPrefix, 0, amountGroups * 2);
final Rollout dynamicRollout = testdataFactory.createRolloutByVariables("dynamic", "static rollout", amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "0", "30", ActionType.FORCED, 1000, false, true);
rolloutManagement.start(dynamicRollout.getId());
rolloutHandler.handleAll();
assertRollout(dynamicRollout, true, RolloutStatus.RUNNING, amountGroups + 1, amountGroups * 2);
final List<RolloutGroup> dynamicGroups = rolloutGroupManagement.findByRollout(
new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id")),
dynamicRollout.getId()).getContent();
for (int i = 0; i < dynamicGroups.size(); i++) {
final RolloutGroup group = dynamicGroups.get(i);
if (i + 1 == dynamicGroups.size()) {
assertGroup(group, true, RolloutGroupStatus.SCHEDULED, 0);
} else {
assertGroup(group, false, RolloutGroupStatus.RUNNING, 2);
}
private static Map<TotalTargetCountStatus.Status, Long> createInitStatusMap() {
final Map<TotalTargetCountStatus.Status, Long> map = new HashMap<>();
for (final TotalTargetCountStatus.Status status : TotalTargetCountStatus.Status.values()) {
map.put(status, 0L);
}
assertAndGetRunning(dynamicRollout, 2).forEach(this::finishAction);
return map;
}
@Step("Finish three actions of the rollout group and delete two targets")
private void finishActionAndDeleteTargetsOfFirstRunningGroup(final Rollout createdRollout) {
// finish group one by finishing targets and deleting targets
final Slice<JpaAction> runningActionsSlice = actionRepository.findByRolloutIdAndStatus(PAGE,
createdRollout.getId(), Status.RUNNING);
final List<JpaAction> runningActions = runningActionsSlice.getContent();
finishAction(runningActions.get(0));
finishAction(runningActions.get(1));
finishAction(runningActions.get(2));
targetManagement.delete(
Arrays.asList(runningActions.get(3).getTarget().getId(), runningActions.get(4).getTarget().getId()));
}
@Step("Check the status of the rollout groups, second group should be in running status")
private void checkSecondGroupStatusIsRunning(final Rollout createdRollout) {
rolloutHandler.handleAll();
for (int i = 0; i < dynamicGroups.size(); i++) {
final RolloutGroup group = dynamicGroups.get(i);
if (i + 1 == dynamicGroups.size()) {
assertGroup(group, true, RolloutGroupStatus.RUNNING, 0);
} else {
assertGroup(group, false, RolloutGroupStatus.FINISHED, 2);
final List<RolloutGroup> runningRolloutGroups = rolloutGroupManagement
.findByRollout(new OffsetBasedPageRequest(0, 10, Sort.by(Direction.ASC, "id")), createdRollout.getId())
.getContent();
assertThat(runningRolloutGroups.get(0).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
assertThat(runningRolloutGroups.get(1).getStatus()).isEqualTo(RolloutGroupStatus.RUNNING);
assertThat(runningRolloutGroups.get(2).getStatus()).isEqualTo(RolloutGroupStatus.SCHEDULED);
}
@Step("Finish one action of the rollout group and delete four targets")
private void finishActionAndDeleteTargetsOfSecondRunningGroup(final Rollout createdRollout) {
final Slice<JpaAction> runningActionsSlice = actionRepository.findByRolloutIdAndStatus(PAGE,
createdRollout.getId(), Status.RUNNING);
final List<JpaAction> runningActions = runningActionsSlice.getContent();
finishAction(runningActions.get(0));
targetManagement.delete(
Arrays.asList(runningActions.get(1).getTarget().getId(), runningActions.get(2).getTarget().getId(),
runningActions.get(3).getTarget().getId(), runningActions.get(4).getTarget().getId()));
}
@Step("Delete all targets of the rollout group")
private void deleteAllTargetsFromThirdGroup(final Rollout createdRollout) {
final Slice<JpaAction> runningActionsSlice = actionRepository.findByRolloutIdAndStatus(PAGE,
createdRollout.getId(), Status.SCHEDULED);
final List<JpaAction> runningActions = runningActionsSlice.getContent();
targetManagement.delete(Arrays.asList(runningActions.get(0).getTarget().getId(),
runningActions.get(1).getTarget().getId(), runningActions.get(2).getTarget().getId(),
runningActions.get(3).getTarget().getId(), runningActions.get(4).getTarget().getId()));
}
@Step("Check the status of the rollout groups and the rollout")
private void verifyRolloutAndAllGroupsAreFinished(final Rollout createdRollout) {
rolloutHandler.handleAll();
final List<RolloutGroup> runningRolloutGroups = rolloutGroupManagement
.findByRollout(PAGE, createdRollout.getId()).getContent();
assertThat(runningRolloutGroups.get(0).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
assertThat(runningRolloutGroups.get(1).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
assertThat(runningRolloutGroups.get(2).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
assertThat(reloadRollout(createdRollout).getStatus()).isEqualTo(RolloutStatus.FINISHED);
}
private Rollout reloadRollout(final Rollout r) {
return getRollout(r.getId());
}
private Rollout getRollout(final Long myRolloutId) {
return rolloutManagement.get(myRolloutId).orElseThrow(NoSuchElementException::new);
}
private void assertRolloutGroup(final long rolloutGroupId, final RolloutGroupStatus status,
final boolean isConfirmationRequired, final long totalTargets, final Status actionStatusToCheck) {
assertThat(rolloutGroupManagement.get(rolloutGroupId)).hasValueSatisfying(rolloutGroup -> {
assertThat(rolloutGroup.getStatus()).isEqualTo(status);
assertThat(rolloutGroup.isConfirmationRequired()).isEqualTo(isConfirmationRequired);
assertThat(rolloutGroup.getTotalTargets()).isEqualTo(totalTargets);
if (actionStatusToCheck != null) {
assertAllActionOfRolloutGroupHavingStatus(rolloutGroup.getId(), actionStatusToCheck);
}
});
}
private void assertAllActionOfRolloutGroupHavingStatus(final long rolloutGroupId, final Status status) {
final List<Target> targets = rolloutGroupManagement.findTargetsOfRolloutGroup(PAGE, rolloutGroupId)
.getContent();
targets.forEach(target -> {
final List<Action> activeActions = deploymentManagement
.findActionsByTarget(target.getControllerId(), PAGE).getContent();
assertThat(activeActions).hasSize(1);
assertThat(activeActions.get(0).getStatus()).isEqualTo(status);
});
}
private void forceQuitAllActionsOfRolloutGroup(final long rolloutGroupId) {
final List<Target> targets = rolloutGroupManagement.findTargetsOfRolloutGroup(PAGE, rolloutGroupId)
.getContent();
targets.forEach(target -> {
deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()).getContent().stream().map(Identifiable::getId)
.forEach(actionId -> {
deploymentManagement.cancelAction(actionId);
deploymentManagement.forceQuitAction(actionId);
});
});
}
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage,
final String targetFilter) {
return generateRolloutGroup(index, percentage, targetFilter, false);
}
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage,
final String targetFilter, final boolean confirmationRequired) {
return entityFactory.rolloutGroup().create().name("Group" + index).description("Group" + index + "desc")
.targetPercentage(Float.valueOf(percentage)).targetFilterQuery(targetFilter)
.confirmationRequired(confirmationRequired);
}
private RolloutCreate generateTargetsAndRollout(final String rolloutName, final int amountTargetsForRollout) {
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
testdataFactory.createTargets(amountTargetsForRollout, rolloutName + "-", rolloutName);
return entityFactory.rollout().create().name(rolloutName)
.description("This is a test description for the rollout")
.targetFilterQuery("controllerId==" + rolloutName + "-*").distributionSetId(distributionSet);
}
private void validateRolloutGroupActionStatus(final RolloutGroup rolloutGroup,
final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus) {
final RolloutGroup rolloutGroupWithDetail = rolloutGroupManagement.getWithDetailedStatus(rolloutGroup.getId())
.get();
validateStatus(rolloutGroupWithDetail.getTotalTargetCountStatus(), expectedTargetCountStatus);
}
private void validateRolloutActionStatus(final Long rolloutId,
final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus) {
final Rollout rolloutWithDetail = rolloutManagement.getWithDetailedStatus(rolloutId).get();
validateStatus(rolloutWithDetail.getTotalTargetCountStatus(), expectedTargetCountStatus);
}
private void validateStatus(final TotalTargetCountStatus totalTargetCountStatus,
final Map<TotalTargetCountStatus.Status, Long> expectedTotalCountStates) {
for (final Map.Entry<TotalTargetCountStatus.Status, Long> entry : expectedTotalCountStates.entrySet()) {
final Long countReady = totalTargetCountStatus.getTotalTargetCountByStatus(entry.getKey());
assertThat(countReady).as("targets in status " + entry.getKey()).isEqualTo(entry.getValue());
}
assertAndGetRunning(dynamicRollout, 0);
rolloutHandler.handleAll();
// NB: asserts that dynamic group doesn't get from its static groups (already finished action targets)
assertGroup(dynamicGroups.get(dynamicGroups.size() - 1), true, RolloutGroupStatus.RUNNING, 0);
assertAndGetRunning(dynamicRollout, 0);
rolloutManagement.pauseRollout(dynamicRollout.getId());
rolloutHandler.handleAll();
}
testdataFactory.createTargets(targetPrefix, amountGroups * 2, amountGroups);
final Rollout staticRollout = testdataFactory.createRolloutByVariables("static", "static rollout", amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "0", "30", ActionType.FORCED, 0, false, false);
rolloutManagement.start(staticRollout.getId());
rolloutHandler.handleAll();
assertRollout(staticRollout, false, RolloutStatus.RUNNING, amountGroups, amountGroups * 3);
final List<RolloutGroup> staticGroups = rolloutGroupManagement.findByRollout(
new OffsetBasedPageRequest(0, amountGroups + 10, Sort.by(Direction.ASC, "id")),
staticRollout.getId()).getContent();
staticGroups.forEach(group -> assertGroup(group, false, RolloutGroupStatus.RUNNING, 3));
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
final String targetPrefixName) {
return createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout, groupSize, successCondition,
errorCondition, rolloutName, targetPrefixName, null);
}
rolloutManagement.resumeRollout(dynamicRollout.getId());
rolloutHandler.handleAll(); // resume, do not get last devices (they are assigned to a newer group, nevertheless newer is with bigger weight
assertGroup(dynamicGroups.get(dynamicGroups.size() - 1), true, RolloutGroupStatus.RUNNING, 0);
assertAndGetRunning(dynamicRollout, 0);
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
final String targetPrefixName, final Integer weight) {
final DistributionSet dsForRolloutTwo = testdataFactory.createDistributionSet("dsFor" + rolloutName);
testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName);
return testdataFactory.createRolloutByVariables(rolloutName, rolloutName + "description", groupSize,
"controllerId==" + targetPrefixName + "-*", dsForRolloutTwo, successCondition, errorCondition,
Action.ActionType.FORCED, weight, false);
}
private int changeStatusForAllRunningActions(final Rollout rollout, final Status status) {
final List<Action> runningActions = findActionsByRolloutAndStatus(rollout, Status.RUNNING);
for (final Action action : runningActions) {
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(status));
}
return runningActions.size();
}
private int changeStatusForRunningActions(final Rollout rollout, final Status status,
final int amountOfTargetsToGetChanged) {
final List<Action> runningActions = findActionsByRolloutAndStatus(rollout, Status.RUNNING);
assertThat(runningActions.size()).isGreaterThanOrEqualTo(amountOfTargetsToGetChanged);
for (int i = 0; i < amountOfTargetsToGetChanged; i++) {
controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(runningActions.get(i).getId()).status(status));
}
return runningActions.size();
}
private void awaitRunningState(final Long myRolloutId) {
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofMillis(500)).with()
.until(() -> SecurityContextSwitch
.runAsPrivileged(
() -> rolloutManagement.get(myRolloutId).orElseThrow(NoSuchElementException::new))
.getStatus().equals(RolloutStatus.RUNNING));
}
}

View File

@@ -14,7 +14,6 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -23,6 +22,9 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
@@ -40,9 +42,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
@@ -54,12 +54,6 @@ import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Software Module Management")
@@ -220,25 +214,6 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
.isEqualTo(ah);
}
private Action assignSet(final JpaTarget target, final JpaDistributionSet ds) {
assignDistributionSet(ds.getId(), target.getControllerId());
implicitLock(ds);
assertThat(targetManagement.getByControllerID(target.getControllerId()).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.PENDING);
final Optional<DistributionSet> assignedDistributionSet = deploymentManagement
.getAssignedDistributionSet(target.getControllerId());
assertThat(assignedDistributionSet).contains(ds);
final Action action = actionRepository
.findAll(
(root, query, cb) ->
cb.and(
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.id), target.getId()),
cb.equal(root.get(JpaAction_.distributionSet).get(JpaDistributionSet_.id), ds.getId())),
PAGE).getContent().get(0);;
assertThat(action).isNotNull();
return action;
}
@Test
@Description("Searches for software modules based on a list of IDs.")
public void findSoftwareModulesById() {
@@ -482,52 +457,6 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
assertThat(artifactRepository.findById(artifactY.getId())).isNotNull();
}
private SoftwareModule createSoftwareModuleWithArtifacts(final SoftwareModuleType type, final String name,
final String version, final int numberArtifacts) {
final long countSoftwareModule = softwareModuleRepository.count();
// create SoftwareModule
SoftwareModule softwareModule = softwareModuleManagement.create(entityFactory.softwareModule().create()
.type(type).name(name).version(version).description("description of artifact " + name));
final int artifactSize = 5 * 1024;
for (int i = 0; i < numberArtifacts; i++) {
artifactManagement.create(new ArtifactUpload(new RandomGeneratedInputStream(artifactSize),
softwareModule.getId(), "file" + (i + 1), false, artifactSize));
}
// Verify correct Creation of SoftwareModule and corresponding artifacts
softwareModule = softwareModuleManagement.get(softwareModule.getId()).get();
assertThat(softwareModuleRepository.findAll()).hasSize((int) countSoftwareModule + 1);
final List<Artifact> artifacts = softwareModule.getArtifacts();
assertThat(artifacts).hasSize(numberArtifacts);
if (numberArtifacts != 0) {
assertArtifactNotNull(artifacts.toArray(new Artifact[artifacts.size()]));
}
artifacts.forEach(artifact -> assertThat(artifactRepository.findById(artifact.getId())).isNotNull());
return softwareModule;
}
private void assertArtifactNotNull(final Artifact... results) {
assertThat(artifactRepository.findAll()).hasSize(results.length);
for (final Artifact result : results) {
assertThat(result.getId()).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNotNull();
}
}
private void assertArtifactNull(final Artifact... results) {
for (final Artifact result : results) {
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNull();
}
}
@Test
@Description("Verfies that all undeleted software modules are found in the repository.")
public void countSoftwareModuleTypesAll() {
@@ -719,103 +648,16 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
assertThat(softwareModuleManagement.findMetaDataBySoftwareModuleId(PageRequest.of(0, 10), swModule.getId())
.getContent()).as("Contains the created metadata element").allSatisfy(metadata -> {
assertThat(metadata.getSoftwareModule().getId()).isEqualTo(swModule.getId());
assertThat(metadata.getKey()).isEqualTo(knownKey1);
assertThat(metadata.getValue()).isEqualTo(knownValue1);
});
assertThat(metadata.getSoftwareModule().getId()).isEqualTo(swModule.getId());
assertThat(metadata.getKey()).isEqualTo(knownKey1);
assertThat(metadata.getValue()).isEqualTo(knownValue1);
});
softwareModuleManagement.deleteMetaData(swModule.getId(), knownKey1);
assertThat(softwareModuleManagement.findMetaDataBySoftwareModuleId(PageRequest.of(0, 10), swModule.getId())
.getContent()).as("Metadata elements are").isEmpty();
}
@Test
@Description("Locks a SM.")
void lockSoftwareModule() {
final SoftwareModule softwareModule = testdataFactory.createSoftwareModule("sm-1");
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(true))
.isFalse();
softwareModuleManagement.lock(softwareModule.getId());
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(false))
.isTrue();
}
@Test
@Description("Unlocks a SM.")
void unlockSoftwareModule() {
final SoftwareModule softwareModule = testdataFactory.createSoftwareModule("sm-1");
softwareModuleManagement.lock(softwareModule.getId());
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(false))
.isTrue();
softwareModuleManagement.unlock(softwareModule.getId());
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(true))
.isFalse();
}
@Test
@Description("Artifacts of a locked SM can't be modified. Expected behaviour is to throw an exception and to do not modify them.")
void lockSoftwareModuleApplied() {
final SoftwareModule softwareModule = testdataFactory.createSoftwareModule("sm-1");
artifactManagement.create(
new ArtifactUpload(new ByteArrayInputStream(new byte[] {1}), softwareModule.getId(),
"artifact1", false, 1));
final int artifactCount = softwareModuleManagement.get(softwareModule.getId()).get().getArtifacts().size();
assertThat(artifactCount).isNotEqualTo(0);
softwareModuleManagement.lock(softwareModule.getId());
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(false))
.isTrue();
// try add
assertThatExceptionOfType(LockedException.class)
.as("Attempt to modify a locked SM artifacts should throw an exception")
.isThrownBy(() -> artifactManagement.create(
new ArtifactUpload(new ByteArrayInputStream(new byte[] {2}), softwareModule.getId(),
"artifact2", false, 1)));
assertThat(softwareModuleManagement.get(softwareModule.getId()).get().getArtifacts().size())
.as("Artifacts shall not be added to a locked SM.")
.isEqualTo(artifactCount);
// try remove
final long artifactId = softwareModuleManagement.get(softwareModule.getId()).get()
.getArtifacts().stream().findFirst().get().getId();
assertThatExceptionOfType(LockedException.class)
.as("Attempt to modify a locked SM artifacts should throw an exception")
.isThrownBy(() -> artifactManagement.delete(artifactId));
assertThat(softwareModuleManagement.get(softwareModule.getId()).get().getArtifacts().size())
.as("Artifact shall not be removed from a locked SM.")
.isEqualTo(artifactCount);
assertThat(artifactManagement.get(artifactId))
.as("Artifact shall not be removed if belongs to a locked SM.")
.isPresent();
}
@Test
@Description("Artifacts of a locked SM can't be modified. Expected behaviour is to throw an exception and to do not modify them.")
void lockedContainingDistributionSetApplied() {
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds-1");
final List<SoftwareModule> modules = distributionSet.getModules().stream().toList();
assertThat(modules.size()).isGreaterThan(1);
// try delete while DS is not locked
softwareModuleManagement.delete(modules.get(0).getId());
distributionSetManagement.lock(distributionSet.getId());
assertThat(
distributionSetManagement.get(distributionSet.getId()).map(DistributionSet::isLocked).orElse(false))
.isTrue();
// try delete SM of a locked DS
assertThatExceptionOfType(LockedException.class)
.as("Attempt to delete a software module of a locked DS should throw an exception")
.isThrownBy(() -> softwareModuleManagement.delete(modules.get(1).getId()));
}
@Test
@Description("Verifies that non existing metadata find results in exception.")
public void findSoftwareModuleMetadataFailsIfEntryDoesNotExist() {
@@ -874,4 +716,156 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
assertThat(metadataSw2.getNumberOfElements()).isZero();
assertThat(metadataSw2.getTotalElements()).isZero();
}
@Test
@Description("Locks a SM.")
void lockSoftwareModule() {
final SoftwareModule softwareModule = testdataFactory.createSoftwareModule("sm-1");
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(true))
.isFalse();
softwareModuleManagement.lock(softwareModule.getId());
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(false))
.isTrue();
}
@Test
@Description("Unlocks a SM.")
void unlockSoftwareModule() {
final SoftwareModule softwareModule = testdataFactory.createSoftwareModule("sm-1");
softwareModuleManagement.lock(softwareModule.getId());
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(false))
.isTrue();
softwareModuleManagement.unlock(softwareModule.getId());
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(true))
.isFalse();
}
@Test
@Description("Artifacts of a locked SM can't be modified. Expected behaviour is to throw an exception and to do not modify them.")
void lockSoftwareModuleApplied() {
final SoftwareModule softwareModule = testdataFactory.createSoftwareModule("sm-1");
artifactManagement.create(
new ArtifactUpload(new ByteArrayInputStream(new byte[] { 1 }), softwareModule.getId(),
"artifact1", false, 1));
final int artifactCount = softwareModuleManagement.get(softwareModule.getId()).get().getArtifacts().size();
assertThat(artifactCount).isNotEqualTo(0);
softwareModuleManagement.lock(softwareModule.getId());
assertThat(
softwareModuleManagement.get(softwareModule.getId()).map(SoftwareModule::isLocked).orElse(false))
.isTrue();
// try add
assertThatExceptionOfType(LockedException.class)
.as("Attempt to modify a locked SM artifacts should throw an exception")
.isThrownBy(() -> artifactManagement.create(
new ArtifactUpload(new ByteArrayInputStream(new byte[] { 2 }), softwareModule.getId(),
"artifact2", false, 1)));
assertThat(softwareModuleManagement.get(softwareModule.getId()).get().getArtifacts().size())
.as("Artifacts shall not be added to a locked SM.")
.isEqualTo(artifactCount);
// try remove
final long artifactId = softwareModuleManagement.get(softwareModule.getId()).get()
.getArtifacts().stream().findFirst().get().getId();
assertThatExceptionOfType(LockedException.class)
.as("Attempt to modify a locked SM artifacts should throw an exception")
.isThrownBy(() -> artifactManagement.delete(artifactId));
assertThat(softwareModuleManagement.get(softwareModule.getId()).get().getArtifacts().size())
.as("Artifact shall not be removed from a locked SM.")
.isEqualTo(artifactCount);
assertThat(artifactManagement.get(artifactId))
.as("Artifact shall not be removed if belongs to a locked SM.")
.isPresent();
}
@Test
@Description("Artifacts of a locked SM can't be modified. Expected behaviour is to throw an exception and to do not modify them.")
void lockedContainingDistributionSetApplied() {
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds-1");
final List<SoftwareModule> modules = distributionSet.getModules().stream().toList();
assertThat(modules.size()).isGreaterThan(1);
// try delete while DS is not locked
softwareModuleManagement.delete(modules.get(0).getId());
distributionSetManagement.lock(distributionSet.getId());
assertThat(
distributionSetManagement.get(distributionSet.getId()).map(DistributionSet::isLocked).orElse(false))
.isTrue();
// try delete SM of a locked DS
assertThatExceptionOfType(LockedException.class)
.as("Attempt to delete a software module of a locked DS should throw an exception")
.isThrownBy(() -> softwareModuleManagement.delete(modules.get(1).getId()));
}
private Action assignSet(final JpaTarget target, final JpaDistributionSet ds) {
assignDistributionSet(ds.getId(), target.getControllerId());
implicitLock(ds);
assertThat(targetManagement.getByControllerID(target.getControllerId()).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.PENDING);
final Optional<DistributionSet> assignedDistributionSet = deploymentManagement
.getAssignedDistributionSet(target.getControllerId());
assertThat(assignedDistributionSet).contains(ds);
final Action action = actionRepository
.findAll(
(root, query, cb) ->
cb.and(
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.id), target.getId()),
cb.equal(root.get(JpaAction_.distributionSet).get(JpaDistributionSet_.id), ds.getId())),
PAGE).getContent().get(0);
;
assertThat(action).isNotNull();
return action;
}
private SoftwareModule createSoftwareModuleWithArtifacts(final SoftwareModuleType type, final String name,
final String version, final int numberArtifacts) {
final long countSoftwareModule = softwareModuleRepository.count();
// create SoftwareModule
SoftwareModule softwareModule = softwareModuleManagement.create(entityFactory.softwareModule().create()
.type(type).name(name).version(version).description("description of artifact " + name));
final int artifactSize = 5 * 1024;
for (int i = 0; i < numberArtifacts; i++) {
artifactManagement.create(new ArtifactUpload(new RandomGeneratedInputStream(artifactSize),
softwareModule.getId(), "file" + (i + 1), false, artifactSize));
}
// Verify correct Creation of SoftwareModule and corresponding artifacts
softwareModule = softwareModuleManagement.get(softwareModule.getId()).get();
assertThat(softwareModuleRepository.findAll()).hasSize((int) countSoftwareModule + 1);
final List<Artifact> artifacts = softwareModule.getArtifacts();
assertThat(artifacts).hasSize(numberArtifacts);
if (numberArtifacts != 0) {
assertArtifactNotNull(artifacts.toArray(new Artifact[artifacts.size()]));
}
artifacts.forEach(artifact -> assertThat(artifactRepository.findById(artifact.getId())).isNotNull());
return softwareModule;
}
private void assertArtifactNotNull(final Artifact... results) {
assertThat(artifactRepository.findAll()).hasSize(results.length);
for (final Artifact result : results) {
assertThat(result.getId()).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNotNull();
}
}
private void assertArtifactNull(final Artifact... results) {
for (final Artifact result : results) {
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNull();
}
}
}

View File

@@ -17,6 +17,9 @@ import java.util.List;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
@@ -27,10 +30,6 @@ import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Software Module Management")
public class SoftwareModuleTypeManagementTest extends AbstractJpaIntegrationTest {

View File

@@ -15,6 +15,9 @@ import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.Random;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
@@ -27,10 +30,6 @@ import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("System Management")
@ExtendWith(DisposableSqlTestDatabaseExtension.class)
@@ -135,25 +134,25 @@ public class SystemManagementTest extends AbstractJpaIntegrationTest {
final String tenantname = "tenant" + i;
SecurityContextSwitch.runAs(SecurityContextSwitch.withUserAndTenant("bumlux", tenantname, true, true, false,
SpringEvalExpressions.SYSTEM_ROLE), () -> {
systemManagement.getTenantMetadata();
if (artifactSize > 0) {
createTestArtifact(random);
createDeletedTestArtifact(random);
}
if (targets > 0) {
final List<Target> createdTargets = createTestTargets(targets);
if (updates > 0) {
for (int x = 0; x < updates; x++) {
final DistributionSet ds = testdataFactory
.createDistributionSet("to be deployed" + x, true);
systemManagement.getTenantMetadata();
if (artifactSize > 0) {
createTestArtifact(random);
createDeletedTestArtifact(random);
}
if (targets > 0) {
final List<Target> createdTargets = createTestTargets(targets);
if (updates > 0) {
for (int x = 0; x < updates; x++) {
final DistributionSet ds = testdataFactory
.createDistributionSet("to be deployed" + x, true);
assignDistributionSet(ds, createdTargets);
}
}
assignDistributionSet(ds, createdTargets);
}
}
}
return null;
});
return null;
});
}
return random;

View File

@@ -22,6 +22,10 @@ import java.util.List;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.assertj.core.api.Assertions;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
@@ -49,14 +53,8 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
/**
* Test class for {@link TargetFilterQueryManagement}.
*
*/
@Feature("Component Tests - Repository")
@Story("Target Filter Query Management")
@@ -93,7 +91,7 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
"TargetFilterQuery");
verifyThrownExceptionBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(NOT_EXIST_IDL)),
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(NOT_EXIST_IDL)),
"DistributionSet");
verifyThrownExceptionBy(
@@ -102,7 +100,7 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
"TargetFilterQuery");
verifyThrownExceptionBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(NOT_EXIST_IDL)),
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(NOT_EXIST_IDL)),
"DistributionSet");
}
@@ -214,65 +212,6 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
verifyAutoAssignmentWithSoftDeletedDs(targetFilterQuery);
}
@Step
private void verifyAutoAssignmentWithDefaultActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()));
implicitLock(distributionSet);
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.FORCED);
}
@Step
private void verifyAutoAssignmentWithSoftActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()).actionType(ActionType.SOFT));
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.SOFT);
}
@Step
private void verifyAutoAssignmentWithDownloadOnlyActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId())
.ds(distributionSet.getId()).actionType(ActionType.DOWNLOAD_ONLY));
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.DOWNLOAD_ONLY);
}
@Step
private void verifyAutoAssignmentWithInvalidActionType(final TargetFilterQuery targetFilterQuery,
final DistributionSet distributionSet) {
// assigning a distribution set with TIMEFORCED action is supposed to
// fail as only FORCED and SOFT action types are allowed
assertThatExceptionOfType(InvalidAutoAssignActionTypeException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId())
.ds(distributionSet.getId()).actionType(ActionType.TIMEFORCED)));
}
@Step
private void verifyAutoAssignmentWithIncompleteDs(final TargetFilterQuery targetFilterQuery) {
final DistributionSet incompleteDistributionSet = distributionSetManagement
.create(entityFactory.distributionSet().create().name("incomplete").version("1")
.type(testdataFactory.findOrCreateDefaultTestDsType()));
assertThatExceptionOfType(IncompleteDistributionSetException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(incompleteDistributionSet.getId())));
}
@Step
private void verifyAutoAssignmentWithSoftDeletedDs(final TargetFilterQuery targetFilterQuery) {
final DistributionSet softDeletedDs = testdataFactory.createDistributionSet("softDeleted");
assignDistributionSet(softDeletedDs, testdataFactory.createTarget("forSoftDeletedDs"));
distributionSetManagement.delete(softDeletedDs.getId());
assertThatExceptionOfType(DeletedException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(softDeletedDs.getId())));
}
@Test
@Description("Assigns a distribution set to an existing filter query and verifies that the quota 'max targets per auto assignment' is enforced.")
public void assignDistributionSetToTargetFilterQueryThatExceedsQuota() {
@@ -407,39 +346,6 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
verifyFindForAllWithAutoAssignDs(tfq, tfq2);
}
@Step
private void verifyFindByDistributionSetAndRsql(final DistributionSet distributionSet, final String rsql,
final TargetFilterQuery... expectedFilterQueries) {
final Page<TargetFilterQuery> tfqList = targetFilterQueryManagement
.findByAutoAssignDSAndRsql(PageRequest.of(0, 500), distributionSet.getId(), rsql);
assertThat(tfqList.getTotalElements()).isEqualTo(expectedFilterQueries.length);
verifyExpectedFilterQueriesInList(tfqList, expectedFilterQueries);
}
private void verifyExpectedFilterQueriesInList(final Slice<TargetFilterQuery> tfqList,
final TargetFilterQuery... expectedFilterQueries) {
assertThat(tfqList.map(TargetFilterQuery::getId)).containsExactly(
Arrays.stream(expectedFilterQueries).map(TargetFilterQuery::getId).toArray(Long[]::new));
}
@Step
private void verifyFindForAllWithAutoAssignDs(final TargetFilterQuery... expectedFilterQueries) {
final Slice<TargetFilterQuery> tfqList = targetFilterQueryManagement
.findWithAutoAssignDS(PageRequest.of(0, 500));
assertThat(tfqList.getNumberOfElements()).isEqualTo(expectedFilterQueries.length);
verifyExpectedFilterQueriesInList(tfqList, expectedFilterQueries);
}
private void verifyExpectedFilterQueriesInList(final Page<TargetFilterQuery> tfqList,
final TargetFilterQuery... expectedFilterQueries) {
assertThat(expectedFilterQueries).as("Target filter query count").hasSize((int) tfqList.getTotalElements());
assertThat(tfqList.map(TargetFilterQuery::getId)).containsExactly(
Arrays.stream(expectedFilterQueries).map(TargetFilterQuery::getId).toArray(Long[]::new));
}
@Test
@Description("Creating or updating a target filter query with autoassignment and no-value weight when multi assignment in enabled.")
public void weightNotRequiredInMultiAssignmentMode() {
@@ -462,9 +368,9 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")).getId();
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
.name("b").query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(342));
.name("b").query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(342));
targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()).weight(343));
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()).weight(343));
}
@Test
@@ -563,6 +469,98 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
.ds(incompleteDistributionSet.getId())));
}
@Step
private void verifyAutoAssignmentWithDefaultActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()));
implicitLock(distributionSet);
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.FORCED);
}
@Step
private void verifyAutoAssignmentWithSoftActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()).actionType(ActionType.SOFT));
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.SOFT);
}
@Step
private void verifyAutoAssignmentWithDownloadOnlyActionType(final String filterName,
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId())
.ds(distributionSet.getId()).actionType(ActionType.DOWNLOAD_ONLY));
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.DOWNLOAD_ONLY);
}
@Step
private void verifyAutoAssignmentWithInvalidActionType(final TargetFilterQuery targetFilterQuery,
final DistributionSet distributionSet) {
// assigning a distribution set with TIMEFORCED action is supposed to
// fail as only FORCED and SOFT action types are allowed
assertThatExceptionOfType(InvalidAutoAssignActionTypeException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId())
.ds(distributionSet.getId()).actionType(ActionType.TIMEFORCED)));
}
@Step
private void verifyAutoAssignmentWithIncompleteDs(final TargetFilterQuery targetFilterQuery) {
final DistributionSet incompleteDistributionSet = distributionSetManagement
.create(entityFactory.distributionSet().create().name("incomplete").version("1")
.type(testdataFactory.findOrCreateDefaultTestDsType()));
assertThatExceptionOfType(IncompleteDistributionSetException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(incompleteDistributionSet.getId())));
}
@Step
private void verifyAutoAssignmentWithSoftDeletedDs(final TargetFilterQuery targetFilterQuery) {
final DistributionSet softDeletedDs = testdataFactory.createDistributionSet("softDeleted");
assignDistributionSet(softDeletedDs, testdataFactory.createTarget("forSoftDeletedDs"));
distributionSetManagement.delete(softDeletedDs.getId());
assertThatExceptionOfType(DeletedException.class)
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(targetFilterQuery.getId()).ds(softDeletedDs.getId())));
}
@Step
private void verifyFindByDistributionSetAndRsql(final DistributionSet distributionSet, final String rsql,
final TargetFilterQuery... expectedFilterQueries) {
final Page<TargetFilterQuery> tfqList = targetFilterQueryManagement
.findByAutoAssignDSAndRsql(PageRequest.of(0, 500), distributionSet.getId(), rsql);
assertThat(tfqList.getTotalElements()).isEqualTo(expectedFilterQueries.length);
verifyExpectedFilterQueriesInList(tfqList, expectedFilterQueries);
}
private void verifyExpectedFilterQueriesInList(final Slice<TargetFilterQuery> tfqList,
final TargetFilterQuery... expectedFilterQueries) {
assertThat(tfqList.map(TargetFilterQuery::getId)).containsExactly(
Arrays.stream(expectedFilterQueries).map(TargetFilterQuery::getId).toArray(Long[]::new));
}
@Step
private void verifyFindForAllWithAutoAssignDs(final TargetFilterQuery... expectedFilterQueries) {
final Slice<TargetFilterQuery> tfqList = targetFilterQueryManagement
.findWithAutoAssignDS(PageRequest.of(0, 500));
assertThat(tfqList.getNumberOfElements()).isEqualTo(expectedFilterQueries.length);
verifyExpectedFilterQueriesInList(tfqList, expectedFilterQueries);
}
private void verifyExpectedFilterQueriesInList(final Page<TargetFilterQuery> tfqList,
final TargetFilterQuery... expectedFilterQueries) {
assertThat(expectedFilterQueries).as("Target filter query count").hasSize((int) tfqList.getTotalElements());
assertThat(tfqList.map(TargetFilterQuery::getId)).containsExactly(
Arrays.stream(expectedFilterQueries).map(TargetFilterQuery::getId).toArray(Long[]::new));
}
private void verifyAutoAssignDsAndActionType(final String filterName, final DistributionSet distributionSet,
final ActionType actionType) {
final TargetFilterQuery tfq = targetFilterQueryManagement.getByName(filterName).get();

View File

@@ -19,6 +19,10 @@ import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.FilterParams;
import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
@@ -39,15 +43,32 @@ import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Target Management Searches")
class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
@Test
@Description("Verifies that targets with given target type are returned from repository.")
public void findTargetByTargetType() {
final TargetType testType = testdataFactory.createTargetType("testType",
Collections.singletonList(standardDsType));
final List<Target> unassigned = testdataFactory.createTargets(9, "unassigned");
final List<Target> assigned = testdataFactory.createTargetsWithType(11, "assigned", testType);
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, false, testType.getId())))
.as("Contains the targets with set type").containsAll(assigned)
.as("and that means the following expected amount").hasSize(11);
assertThat(targetManagement.countByFilters(new FilterParams(null, null, false, testType.getId())))
.as("Count the targets with set type").isEqualTo(11);
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, true, null)))
.as("Contains the targets without a type").containsAll(unassigned)
.as("and that means the following expected amount").hasSize(9);
assertThat(targetManagement.countByFilters(new FilterParams(null, null, true, null)))
.as("Counts the targets without a type").isEqualTo(9);
}
@Test
@Description("Tests different parameter combinations for target search operations. "
+ "That includes both the test itself, as a count operation with the same filters "
@@ -178,382 +199,6 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
verifyThat198TargetsAreInStatusUnknownAndOverdue(unknown, expected);
}
@Step
private void verifyThat1TargetAIsInStatusPendingAndHasDSInstalled(final DistributionSet installedSet,
final List<TargetUpdateStatus> pending, final Target expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, installedSet.getId(), Boolean.FALSE);
final String query = "updatestatus==pending and installedds.name==" + installedSet.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat200targetsWithGivenTagAreInStatusPendingorUnknown(final TargetTag targTagW,
final List<TargetUpdateStatus> both, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(both, null, null, null, Boolean.FALSE, targTagW.getName());
final String query = "(updatestatus==pending or updatestatus==unknown) and tag==" + targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(200).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat2TargetsWithGivenTagAreInPending(final TargetTag targTagW,
final List<TargetUpdateStatus> pending, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, null, Boolean.FALSE,
targTagW.getName());
final String query = "updatestatus==pending and tag==" + targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(2).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat2TargetsWithGivenTagAndDSIsInPending(final TargetTag targTagW, final DistributionSet setA,
final List<TargetUpdateStatus> pending, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, setA.getId(), Boolean.FALSE,
targTagW.getName());
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ") and tag==" + targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(2).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat1TargetWithGivenNameOrDescAndTagAndDSIsInPending(final TargetTag targTagW,
final DistributionSet setA, final List<TargetUpdateStatus> pending, final Target expected) {
final FilterParams filterParams = new FilterParams(pending, null, "%targ-B%", setA.getId(), Boolean.FALSE,
targTagW.getName());
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ") and (name==*targ-B* or description==*targ-B*) and tag==" + targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat1TargetWithGivenNameOrDescAndDSIsInPending(final DistributionSet setA,
final List<TargetUpdateStatus> pending, final Target expected) {
final FilterParams filterParams = new FilterParams(pending, null, "%targ-A%", setA.getId(), Boolean.FALSE);
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ") and (name==*targ-A* or description==*targ-A*)";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat3TargetsWithGivenDSAreInPending(final DistributionSet setA,
final List<TargetUpdateStatus> pending, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, setA.getId(), Boolean.FALSE);
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(3).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat4TargetsAreInStatusPending(final List<TargetUpdateStatus> pending,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, null, Boolean.FALSE);
final String query = "updatestatus==pending";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(4).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat99TargetsWithGivenNameOrDescAndTagAreInStatusUnknown(final TargetTag targTagW,
final List<TargetUpdateStatus> unknown, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, null, "%targ-B%", null, Boolean.FALSE,
targTagW.getName());
final String query = "updatestatus==unknown and (name==*targ-B* or description==*targ-B*) and tag=="
+ targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(99).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat99TargetsWithNameOrDescriptionAreInGivenStatus(final List<TargetUpdateStatus> unknown,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, null, "%targ-A%", null, Boolean.FALSE);
final String query = "updatestatus==unknown and (name==*targ-A* or description==*targ-A*)";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(99).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat0TargetsAreInStatusUnknownAndHaveDSAssigned(final DistributionSet setA,
final List<TargetUpdateStatus> unknown) {
final FilterParams filterParams = new FilterParams(unknown, null, null, setA.getId(), Boolean.FALSE);
final String query = "updatestatus==unknown and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(0).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and filter query returns the same result")
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
}
@Step
private void verifyThat198TargetsAreInStatusUnknownAndHaveGivenTags(final TargetTag targTagY,
final TargetTag targTagW, final List<TargetUpdateStatus> unknown, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, null, null, null, Boolean.FALSE, targTagY.getName(),
targTagW.getName());
final String query = "updatestatus==unknown and (tag==" + targTagY.getName() + " or tag==" + targTagW.getName()
+ ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(198).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat496TargetsAreInStatusUnknown(final List<TargetUpdateStatus> unknown,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, null, null, null, Boolean.FALSE);
final String query = "updatestatus==unknown";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(496).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat198TargetsAreInStatusUnknownAndOverdue(final List<TargetUpdateStatus> unknown,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, Boolean.TRUE, null, null, Boolean.FALSE);
// be careful: simple filters are concatenated using AND-gating
final String query = "lastcontrollerrequestat=le=${overdue_ts};updatestatus==UNKNOWN";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(198).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat1TargetWithDescOrNameHasDS(final DistributionSet setA, final Target expected) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-A%", setA.getId(), Boolean.FALSE);
final String query = "(name==*targ-A* or description==*targ-A*) and (assignedds.name==" + setA.getName()
+ " or installedds.name==" + setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat3TargetsHaveDSAssigned(final DistributionSet setA, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(null, null, null, setA.getId(), Boolean.FALSE);
final String query = "assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(3).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat0TargetsWithNameOrdescAndDSHaveTag(final TargetTag targTagX, final DistributionSet setA) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-C%", setA.getId(), Boolean.FALSE,
targTagX.getName());
final String query = "(name==*targ-C* or description==*targ-C*) and tag==" + targTagX.getName()
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(0).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and filter query returns the same result")
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
}
@Step
private void verifyThat0TargetsWithTagAndDescOrNameHasDS(final TargetTag targTagW, final DistributionSet setA) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-A%", setA.getId(), Boolean.FALSE,
targTagW.getName());
final String query = "(name==*targ-A* or description==*targ-A*) and tag==" + targTagW.getName()
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(0).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and filter query returns the same result")
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
}
@Step
private void verifyThat1TargetHasTagHasDescOrNameAndDs(final TargetTag targTagW, final DistributionSet setA,
final Target expected) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-C%", setA.getId(), Boolean.FALSE,
targTagW.getName());
final String query = "(name==*targ-c* or description==*targ-C*) and tag==" + targTagW.getName()
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat1TargetHasNameAndId(final String name, final String controllerId) {
final FilterParams filterParamsByName = new FilterParams(null, null, name, null, Boolean.FALSE);
assertThat(targetManagement.findByFilters(PAGE, filterParamsByName).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParamsByName));
final FilterParams filterParamsByControllerId = new FilterParams(null, null, controllerId, null, Boolean.FALSE);
assertThat(targetManagement.findByFilters(PAGE, filterParamsByControllerId).getContent())
.as("has number of elements").hasSize(1).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParamsByControllerId));
}
@Step
private void verifyThat100TargetsContainsGivenTextAndHaveTagAssigned(final TargetTag targTagY,
final TargetTag targTagW, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-B%", null, Boolean.FALSE,
targTagY.getName(), targTagW.getName());
final String query = "(name==*targ-B* or description==*targ-B*) and (tag==" + targTagY.getName() + " or tag=="
+ targTagW.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(100).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@SafeVarargs
private List<Target> concat(final List<Target>... targets) {
final List<Target> result = new ArrayList<>();
Arrays.asList(targets).forEach(result::addAll);
return result;
}
@Step
private void verifyThat200TargetsHaveTagD(final TargetTag targTagD, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(null, null, null, null, Boolean.FALSE, targTagD.getName());
final String query = "tag==" + targTagD.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("Expected number of results is")
.hasSize(200).as("and is expected number of results is equal to ")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThatRepositoryContains500Targets() {
final FilterParams filterParams = new FilterParams(null, null, null, null, null);
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent())
.as("Overall we expect that many targets in the repository").hasSize(500)
.as("which is also reflected by repository count").hasSize((int)targetManagement.count())
.as("which is also reflected by call without specification")
.containsAll(targetManagement.findAll(PAGE).getContent());
}
@Step
private void verifyThat1TargetHasTypeAndDSAssigned(final TargetType type, final DistributionSet set,
final Target expected) {
final FilterParams filterParams = new FilterParams(null, set.getId(), Boolean.FALSE, type.getId());
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected);
}
@Step
private void verifyThatTargetsHasNoTypeAndDSAssignedOrInstalled(final DistributionSet set,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(null, set.getId(), Boolean.TRUE, null);
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(expected.size()).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected);
}
@Step
private void verifyThat100TargetsContainsGivenTextAndHaveTypeAssigned(final TargetType targetType,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams("%targ-E%", null, Boolean.FALSE, targetType.getId());
final List<Target> filteredTargets = targetManagement.findByFilters(PAGE, filterParams).getContent();
assertThat(filteredTargets).as("has number of elements").hasSize(100)
.as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams));
// Comparing the controller ids, as one of the targets was modified, so
// a 1:1
// comparison of the objects is not possible
assertThat(filteredTargets.stream().map(Target::getControllerId).collect(Collectors.toList()))
.containsAll(expected.stream().map(Target::getControllerId).collect(Collectors.toList()));
}
@Step
private void verifyThat400TargetsContainsGivenTextAndHaveNoTypeAssigned(final List<Target> expected) {
final FilterParams filterParams = new FilterParams("%targ-%", null, Boolean.TRUE, null);
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(400).as("that number is also returned by count query")
.hasSize((int)targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected);
}
@Test
@Description("Tests the correct order of targets based on selected distribution set. The system expects to have an order based on installed, assigned DS.")
void targetSearchWithVariousFilterCombinationsAndOrderByDistributionSet() {
@@ -624,11 +269,6 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
assertThatTargetNameEquals(targetsOrderedByDistAndName, 8, notAssigned, 0);
}
private void assertThatTargetNameEquals(final List<Target> targets1, final int index1, final List<Target> targets2,
final int index2) {
assertThat(targets1.get(index1).getName()).isEqualTo(targets2.get(index2).getName());
}
@Test
@Description("Tests the correct order of targets with applied overdue filter based on selected distribution set. The system expects to have an order based on installed, assigned DS.")
void targetSearchWithOverdueFilterAndOrderByDistributionSet() {
@@ -794,32 +434,391 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
.doesNotContainAnyElementsOf(targetsWithIncompatibleType);
}
@Step
private void verifyThat1TargetAIsInStatusPendingAndHasDSInstalled(final DistributionSet installedSet,
final List<TargetUpdateStatus> pending, final Target expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, installedSet.getId(), Boolean.FALSE);
final String query = "updatestatus==pending and installedds.name==" + installedSet.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat200targetsWithGivenTagAreInStatusPendingorUnknown(final TargetTag targTagW,
final List<TargetUpdateStatus> both, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(both, null, null, null, Boolean.FALSE, targTagW.getName());
final String query = "(updatestatus==pending or updatestatus==unknown) and tag==" + targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(200).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat2TargetsWithGivenTagAreInPending(final TargetTag targTagW,
final List<TargetUpdateStatus> pending, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, null, Boolean.FALSE,
targTagW.getName());
final String query = "updatestatus==pending and tag==" + targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(2).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat2TargetsWithGivenTagAndDSIsInPending(final TargetTag targTagW, final DistributionSet setA,
final List<TargetUpdateStatus> pending, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, setA.getId(), Boolean.FALSE,
targTagW.getName());
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ") and tag==" + targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(2).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat1TargetWithGivenNameOrDescAndTagAndDSIsInPending(final TargetTag targTagW,
final DistributionSet setA, final List<TargetUpdateStatus> pending, final Target expected) {
final FilterParams filterParams = new FilterParams(pending, null, "%targ-B%", setA.getId(), Boolean.FALSE,
targTagW.getName());
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ") and (name==*targ-B* or description==*targ-B*) and tag==" + targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat1TargetWithGivenNameOrDescAndDSIsInPending(final DistributionSet setA,
final List<TargetUpdateStatus> pending, final Target expected) {
final FilterParams filterParams = new FilterParams(pending, null, "%targ-A%", setA.getId(), Boolean.FALSE);
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ") and (name==*targ-A* or description==*targ-A*)";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat3TargetsWithGivenDSAreInPending(final DistributionSet setA,
final List<TargetUpdateStatus> pending, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, setA.getId(), Boolean.FALSE);
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(3).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat4TargetsAreInStatusPending(final List<TargetUpdateStatus> pending,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(pending, null, null, null, Boolean.FALSE);
final String query = "updatestatus==pending";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(4).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat99TargetsWithGivenNameOrDescAndTagAreInStatusUnknown(final TargetTag targTagW,
final List<TargetUpdateStatus> unknown, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, null, "%targ-B%", null, Boolean.FALSE,
targTagW.getName());
final String query = "updatestatus==unknown and (name==*targ-B* or description==*targ-B*) and tag=="
+ targTagW.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(99).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat99TargetsWithNameOrDescriptionAreInGivenStatus(final List<TargetUpdateStatus> unknown,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, null, "%targ-A%", null, Boolean.FALSE);
final String query = "updatestatus==unknown and (name==*targ-A* or description==*targ-A*)";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(99).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat0TargetsAreInStatusUnknownAndHaveDSAssigned(final DistributionSet setA,
final List<TargetUpdateStatus> unknown) {
final FilterParams filterParams = new FilterParams(unknown, null, null, setA.getId(), Boolean.FALSE);
final String query = "updatestatus==unknown and (assignedds.name==" + setA.getName() + " or installedds.name=="
+ setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(0).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and filter query returns the same result")
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
}
@Step
private void verifyThat198TargetsAreInStatusUnknownAndHaveGivenTags(final TargetTag targTagY,
final TargetTag targTagW, final List<TargetUpdateStatus> unknown, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, null, null, null, Boolean.FALSE, targTagY.getName(),
targTagW.getName());
final String query = "updatestatus==unknown and (tag==" + targTagY.getName() + " or tag==" + targTagW.getName()
+ ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(198).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat496TargetsAreInStatusUnknown(final List<TargetUpdateStatus> unknown,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, null, null, null, Boolean.FALSE);
final String query = "updatestatus==unknown";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(496).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat198TargetsAreInStatusUnknownAndOverdue(final List<TargetUpdateStatus> unknown,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(unknown, Boolean.TRUE, null, null, Boolean.FALSE);
// be careful: simple filters are concatenated using AND-gating
final String query = "lastcontrollerrequestat=le=${overdue_ts};updatestatus==UNKNOWN";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(198).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat1TargetWithDescOrNameHasDS(final DistributionSet setA, final Target expected) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-A%", setA.getId(), Boolean.FALSE);
final String query = "(name==*targ-A* or description==*targ-A*) and (assignedds.name==" + setA.getName()
+ " or installedds.name==" + setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat3TargetsHaveDSAssigned(final DistributionSet setA, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(null, null, null, setA.getId(), Boolean.FALSE);
final String query = "assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(3).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat0TargetsWithNameOrdescAndDSHaveTag(final TargetTag targTagX, final DistributionSet setA) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-C%", setA.getId(), Boolean.FALSE,
targTagX.getName());
final String query = "(name==*targ-C* or description==*targ-C*) and tag==" + targTagX.getName()
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(0).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and filter query returns the same result")
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
}
@Step
private void verifyThat0TargetsWithTagAndDescOrNameHasDS(final TargetTag targTagW, final DistributionSet setA) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-A%", setA.getId(), Boolean.FALSE,
targTagW.getName());
final String query = "(name==*targ-A* or description==*targ-A*) and tag==" + targTagW.getName()
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(0).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and filter query returns the same result")
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
}
@Step
private void verifyThat1TargetHasTagHasDescOrNameAndDs(final TargetTag targTagW, final DistributionSet setA,
final Target expected) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-C%", setA.getId(), Boolean.FALSE,
targTagW.getName());
final String query = "(name==*targ-c* or description==*targ-C*) and tag==" + targTagW.getName()
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThat1TargetHasNameAndId(final String name, final String controllerId) {
final FilterParams filterParamsByName = new FilterParams(null, null, name, null, Boolean.FALSE);
assertThat(targetManagement.findByFilters(PAGE, filterParamsByName).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParamsByName));
final FilterParams filterParamsByControllerId = new FilterParams(null, null, controllerId, null, Boolean.FALSE);
assertThat(targetManagement.findByFilters(PAGE, filterParamsByControllerId).getContent())
.as("has number of elements").hasSize(1).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParamsByControllerId));
}
@Step
private void verifyThat100TargetsContainsGivenTextAndHaveTagAssigned(final TargetTag targTagY,
final TargetTag targTagW, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(null, null, "%targ-B%", null, Boolean.FALSE,
targTagY.getName(), targTagW.getName());
final String query = "(name==*targ-B* or description==*targ-B*) and (tag==" + targTagY.getName() + " or tag=="
+ targTagW.getName() + ")";
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(100).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@SafeVarargs
private List<Target> concat(final List<Target>... targets) {
final List<Target> result = new ArrayList<>();
Arrays.asList(targets).forEach(result::addAll);
return result;
}
@Step
private void verifyThat200TargetsHaveTagD(final TargetTag targTagD, final List<Target> expected) {
final FilterParams filterParams = new FilterParams(null, null, null, null, Boolean.FALSE, targTagD.getName());
final String query = "tag==" + targTagD.getName();
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("Expected number of results is")
.hasSize(200).as("and is expected number of results is equal to ")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected)
.as("and filter query returns the same result")
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
}
@Step
private void verifyThatRepositoryContains500Targets() {
final FilterParams filterParams = new FilterParams(null, null, null, null, null);
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent())
.as("Overall we expect that many targets in the repository").hasSize(500)
.as("which is also reflected by repository count").hasSize((int) targetManagement.count())
.as("which is also reflected by call without specification")
.containsAll(targetManagement.findAll(PAGE).getContent());
}
@Step
private void verifyThat1TargetHasTypeAndDSAssigned(final TargetType type, final DistributionSet set,
final Target expected) {
final FilterParams filterParams = new FilterParams(null, set.getId(), Boolean.FALSE, type.getId());
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(1).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsExactly(expected);
}
@Step
private void verifyThatTargetsHasNoTypeAndDSAssignedOrInstalled(final DistributionSet set,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams(null, set.getId(), Boolean.TRUE, null);
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(expected.size()).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected);
}
@Step
private void verifyThat100TargetsContainsGivenTextAndHaveTypeAssigned(final TargetType targetType,
final List<Target> expected) {
final FilterParams filterParams = new FilterParams("%targ-E%", null, Boolean.FALSE, targetType.getId());
final List<Target> filteredTargets = targetManagement.findByFilters(PAGE, filterParams).getContent();
assertThat(filteredTargets).as("has number of elements").hasSize(100)
.as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams));
// Comparing the controller ids, as one of the targets was modified, so
// a 1:1
// comparison of the objects is not possible
assertThat(filteredTargets.stream().map(Target::getControllerId).collect(Collectors.toList()))
.containsAll(expected.stream().map(Target::getControllerId).collect(Collectors.toList()));
}
@Step
private void verifyThat400TargetsContainsGivenTextAndHaveNoTypeAssigned(final List<Target> expected) {
final FilterParams filterParams = new FilterParams("%targ-%", null, Boolean.TRUE, null);
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
.hasSize(400).as("that number is also returned by count query")
.hasSize((int) targetManagement.countByFilters(filterParams))
.as("and contains the following elements").containsAll(expected);
}
private void assertThatTargetNameEquals(final List<Target> targets1, final int index1, final List<Target> targets2,
final int index2) {
assertThat(targets1.get(index1).getName()).isEqualTo(targets2.get(index2).getName());
}
private DistributionSet createDistSetWithType(final DistributionSetType type) {
final DistributionSetCreate dsCreate = entityFactory.distributionSet().create().name("test-ds").version("1.0")
.type(type);
return distributionSetManagement.create(dsCreate);
}
@Test
@Description("Verifies that targets with given target type are returned from repository.")
public void findTargetByTargetType() {
final TargetType testType = testdataFactory.createTargetType("testType",
Collections.singletonList(standardDsType));
final List<Target> unassigned = testdataFactory.createTargets(9, "unassigned");
final List<Target> assigned = testdataFactory.createTargetsWithType(11, "assigned", testType);
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, false, testType.getId())))
.as("Contains the targets with set type").containsAll(assigned)
.as("and that means the following expected amount").hasSize(11);
assertThat(targetManagement.countByFilters(new FilterParams(null, null, false, testType.getId())))
.as("Count the targets with set type").isEqualTo(11);
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, true, null)))
.as("Contains the targets without a type").containsAll(unassigned)
.as("and that means the following expected amount").hasSize(9);
assertThat(targetManagement.countByFilters(new FilterParams(null, null, true, null)))
.as("Counts the targets without a type").isEqualTo(9);
}
}

View File

@@ -27,6 +27,10 @@ import java.util.stream.Collectors;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.awaitility.Awaitility;
import org.eclipse.hawkbit.im.authentication.SpPermission;
@@ -82,11 +86,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Target Management")
class TargetManagementTest extends AbstractJpaIntegrationTest {
@@ -252,136 +251,6 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
createAndUpdateTargetWithInvalidAddress(target);
}
@Step
private void createAndUpdateTargetWithInvalidDescription(final Target target) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long description should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a")
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid description should not be created").isThrownBy(() -> targetManagement
.create(entityFactory.target().create().controllerId("a").description(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long description should not be updated")
.isThrownBy(() -> targetManagement.update(entityFactory.target().update(target.getControllerId())
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid description should not be updated").isThrownBy(() -> targetManagement.update(
entityFactory.target().update(target.getControllerId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTargetWithInvalidName(final Target target) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long name should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a")
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid name should not be created").isThrownBy(() -> targetManagement
.create(entityFactory.target().create().controllerId("a").name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long name should not be updated")
.isThrownBy(() -> targetManagement.update(entityFactory.target().update(target.getControllerId())
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid name should not be updated").isThrownBy(() -> targetManagement
.update(entityFactory.target().update(target.getControllerId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too short name should not be updated").isThrownBy(() -> targetManagement
.update(entityFactory.target().update(target.getControllerId()).name("")));
}
@Step
private void createAndUpdateTargetWithInvalidSecurityToken(final Target target) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long token should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a")
.securityToken(RandomStringUtils.randomAlphanumeric(Target.SECURITY_TOKEN_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid token should not be created").isThrownBy(() -> targetManagement
.create(entityFactory.target().create().controllerId("a").securityToken(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long token should not be updated")
.isThrownBy(() -> targetManagement.update(entityFactory.target().update(target.getControllerId())
.securityToken(RandomStringUtils.randomAlphanumeric(Target.SECURITY_TOKEN_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid token should not be updated").isThrownBy(() -> targetManagement.update(
entityFactory.target().update(target.getControllerId()).securityToken(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too short token should not be updated").isThrownBy(() -> targetManagement
.update(entityFactory.target().update(target.getControllerId()).securityToken("")));
}
@Step
private void createAndUpdateTargetWithInvalidAddress(final Target target) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long address should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a")
.address(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(InvalidTargetAddressException.class).as("target with invalid should not be created")
.isThrownBy(() -> targetManagement
.create(entityFactory.target().create().controllerId("a").address(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long address should not be updated")
.isThrownBy(() -> targetManagement.update(entityFactory.target().update(target.getControllerId())
.address(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(InvalidTargetAddressException.class)
.as("target with invalid address should not be updated").isThrownBy(() -> targetManagement
.update(entityFactory.target().update(target.getControllerId()).address(INVALID_TEXT_HTML)));
}
@Step
private void createTargetWithInvalidControllerId() {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with empty controller id should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("")));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with null controller id should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId(null)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long controller id should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create()
.controllerId(RandomStringUtils.randomAlphanumeric(Target.CONTROLLER_ID_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid controller id should not be created").isThrownBy(
() -> targetManagement.create(entityFactory.target().create().controllerId(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class).as(WHITESPACE_ERROR)
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId(" ")));
assertThatExceptionOfType(ConstraintViolationException.class).as(WHITESPACE_ERROR)
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a b")));
assertThatExceptionOfType(ConstraintViolationException.class).as(WHITESPACE_ERROR)
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId(" ")));
assertThatExceptionOfType(ConstraintViolationException.class).as(WHITESPACE_ERROR)
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("aaa bbb")));
}
@Test
@Description("Ensures that targets can assigned and unassigned to a target tag. Not exists target will be ignored for the assignment.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 4),
@@ -450,18 +319,6 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
assertThat(targetManagement.count()).as("target count is wrong").isZero();
}
private Target createTargetWithAttributes(final String controllerId) {
final Map<String, String> testData = new HashMap<>();
testData.put("test1", "testdata1");
targetManagement.create(entityFactory.target().create().controllerId(controllerId));
final Target target = controllerManagement.updateControllerAttributes(controllerId, testData, null);
assertThat(targetManagement.getControllerAttributes(controllerId)).as("Controller Attributes are wrong")
.isEqualTo(testData);
return target;
}
@Test
@Description("Finds a target by given ID and checks if all data is in the response (including the data defined as lazy).")
@ExpectEvents({ @Expect(type = DistributionSetCreatedEvent.class, count = 2),
@@ -554,50 +411,6 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
}
}
/**
* verifies, that all {@link TargetTag} of parameter. NOTE: it's accepted
* that the target have additional tags assigned to them which are not
* contained within parameter tags.
*
* @param strict
* if true, the given targets MUST contain EXACTLY ALL given
* tags, AND NO OTHERS. If false, the given targets MUST contain
* ALL given tags, BUT MAY CONTAIN FURTHER ONE
* @param targets
* targets to be verified
* @param tags
* are contained within tags of all targets.
*/
private void checkTargetHasTags(final boolean strict, final Iterable<Target> targets, final TargetTag... tags) {
_target: for (final Target tl : targets) {
for (final Tag tt : getTargetTags(tl.getControllerId())) {
for (final Tag tag : tags) {
if (tag.getName().equals(tt.getName())) {
continue _target;
}
}
if (strict) {
fail("Target does not contain all tags");
}
}
fail("Target does not contain any tags or the expected tag was not found");
}
}
private void checkTargetHasNotTags(final Iterable<Target> targets, final TargetTag... tags) {
for (final Target tl : targets) {
targetManagement.getByControllerID(tl.getControllerId()).get();
for (final Tag tag : tags) {
for (final Tag tt : getTargetTags(tl.getControllerId())) {
if (tag.getName().equals(tt.getName())) {
fail("Target should have no tags");
}
}
}
}
}
@Test
@WithUser(allSpPermissions = true)
@Description("Creates and updates a target and verifies the changes in the repository.")
@@ -662,7 +475,8 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
.collect(Collectors.toList());
// verify that all entries are found
_founds: for (final Target foundTarget : allFound) {
_founds:
for (final Target foundTarget : allFound) {
for (final Target changedTarget : firstList) {
if (changedTarget.getControllerId().equals(foundTarget.getControllerId())) {
assertThat(changedTarget.getDescription())
@@ -970,13 +784,6 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
assertThat(createdMetadata.getValue()).isEqualTo(knownValue);
}
private JpaTargetMetadata insertTargetMetadata(final String knownKey, final String knownValue,
final Target target) {
final JpaTargetMetadata metadata = new JpaTargetMetadata(knownKey, knownValue, target);
return (JpaTargetMetadata) targetManagement
.createMetaData(target.getControllerId(), Collections.singletonList(metadata)).get(0);
}
@Test
@Description("Verifies the enforcement of the metadata quota per target.")
void createTargetMetadataUntilQuotaIsExceeded() {
@@ -1163,16 +970,6 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
checkTargetsHaveType(typeATargets, typeB);
}
private void checkTargetsHaveType(final List<Target> targets, final TargetType type) {
final List<JpaTarget> foundTargets = targetRepository
.findAllById(targets.stream().map(Identifiable::getId).collect(Collectors.toList()));
for (final Target target : foundTargets) {
if (!type.getName().equals(type.getName())) {
fail(String.format("Target %s is not of type %s.", target, type));
}
}
}
@Test
@Description("Queries and loads the metadata related to a given target.")
void findAllTargetMetadataByControllerId() {
@@ -1193,26 +990,6 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
assertThat(metadataOfTarget2.getTotalElements()).isEqualTo(8);
}
private Target createTargetWithMetadata(final String controllerId, final int count) {
final Target target = testdataFactory.createTarget(controllerId);
for (int index = 1; index <= count; index++) {
insertTargetMetadata("key" + index, controllerId + "-value" + index, target);
}
return target;
}
private Target createTargetWithTargetTypeAndMetadata(final String controllerId, final long targetTypeId, final int count) {
final Target target = testdataFactory.createTarget(controllerId, controllerId, targetTypeId);
for (int index = 1; index <= count; index++) {
insertTargetMetadata("key" + index, controllerId + "-value" + index, target);
}
return target;
}
@Test
@WithUser(allSpPermissions = true)
@Description("Checks that target type is not assigned to target if invalid.")
@@ -1411,7 +1188,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
createAction(targets.get(8), rolloutNewer, 20, Status.DOWNLOADED, distributionSet);
final Slice<Target> matching = targetManagement.findByNotInGEGroupAndNotInActiveActionGEWeightOrInRolloutAndTargetFilterQueryAndCompatibleAndUpdatable(
PAGE, rollout.getId(), 10, Long.MAX_VALUE,"controllerid==dyn_action_filter_*", distributionSet.getType());
PAGE, rollout.getId(), 10, Long.MAX_VALUE, "controllerid==dyn_action_filter_*", distributionSet.getType());
assertThat(matching.getNumberOfElements()).isEqualTo(5);
assertThat(matching.stream()
@@ -1421,7 +1198,239 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
.sorted()
.toList()).isEqualTo(List.of(0, 1, 2, 5, 6));
}
private void createAction(final Target target, final Rollout rollout, final Integer weight, final Action.Status status, final DistributionSet distributionSet) {
@Test
@Description("Target matches filter for not existing DS.")
void matchesFilterDsNotExists() {
final String target = testdataFactory.createTarget().getControllerId();
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
() -> targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, 123, "name==*"));
}
@Step
private void createAndUpdateTargetWithInvalidDescription(final Target target) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long description should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a")
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid description should not be created").isThrownBy(() -> targetManagement
.create(entityFactory.target().create().controllerId("a").description(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long description should not be updated")
.isThrownBy(() -> targetManagement.update(entityFactory.target().update(target.getControllerId())
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid description should not be updated").isThrownBy(() -> targetManagement.update(
entityFactory.target().update(target.getControllerId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTargetWithInvalidName(final Target target) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long name should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a")
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid name should not be created").isThrownBy(() -> targetManagement
.create(entityFactory.target().create().controllerId("a").name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long name should not be updated")
.isThrownBy(() -> targetManagement.update(entityFactory.target().update(target.getControllerId())
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid name should not be updated").isThrownBy(() -> targetManagement
.update(entityFactory.target().update(target.getControllerId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too short name should not be updated").isThrownBy(() -> targetManagement
.update(entityFactory.target().update(target.getControllerId()).name("")));
}
@Step
private void createAndUpdateTargetWithInvalidSecurityToken(final Target target) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long token should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a")
.securityToken(RandomStringUtils.randomAlphanumeric(Target.SECURITY_TOKEN_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid token should not be created").isThrownBy(() -> targetManagement
.create(entityFactory.target().create().controllerId("a").securityToken(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long token should not be updated")
.isThrownBy(() -> targetManagement.update(entityFactory.target().update(target.getControllerId())
.securityToken(RandomStringUtils.randomAlphanumeric(Target.SECURITY_TOKEN_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid token should not be updated").isThrownBy(() -> targetManagement.update(
entityFactory.target().update(target.getControllerId()).securityToken(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too short token should not be updated").isThrownBy(() -> targetManagement
.update(entityFactory.target().update(target.getControllerId()).securityToken("")));
}
@Step
private void createAndUpdateTargetWithInvalidAddress(final Target target) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long address should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a")
.address(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(InvalidTargetAddressException.class).as("target with invalid should not be created")
.isThrownBy(() -> targetManagement
.create(entityFactory.target().create().controllerId("a").address(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long address should not be updated")
.isThrownBy(() -> targetManagement.update(entityFactory.target().update(target.getControllerId())
.address(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(InvalidTargetAddressException.class)
.as("target with invalid address should not be updated").isThrownBy(() -> targetManagement
.update(entityFactory.target().update(target.getControllerId()).address(INVALID_TEXT_HTML)));
}
@Step
private void createTargetWithInvalidControllerId() {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with empty controller id should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("")));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with null controller id should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId(null)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with too long controller id should not be created")
.isThrownBy(() -> targetManagement.create(entityFactory.target().create()
.controllerId(RandomStringUtils.randomAlphanumeric(Target.CONTROLLER_ID_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("target with invalid controller id should not be created").isThrownBy(
() -> targetManagement.create(entityFactory.target().create().controllerId(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class).as(WHITESPACE_ERROR)
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId(" ")));
assertThatExceptionOfType(ConstraintViolationException.class).as(WHITESPACE_ERROR)
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("a b")));
assertThatExceptionOfType(ConstraintViolationException.class).as(WHITESPACE_ERROR)
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId(" ")));
assertThatExceptionOfType(ConstraintViolationException.class).as(WHITESPACE_ERROR)
.isThrownBy(() -> targetManagement.create(entityFactory.target().create().controllerId("aaa bbb")));
}
private Target createTargetWithAttributes(final String controllerId) {
final Map<String, String> testData = new HashMap<>();
testData.put("test1", "testdata1");
targetManagement.create(entityFactory.target().create().controllerId(controllerId));
final Target target = controllerManagement.updateControllerAttributes(controllerId, testData, null);
assertThat(targetManagement.getControllerAttributes(controllerId)).as("Controller Attributes are wrong")
.isEqualTo(testData);
return target;
}
/**
* verifies, that all {@link TargetTag} of parameter. NOTE: it's accepted
* that the target have additional tags assigned to them which are not
* contained within parameter tags.
*
* @param strict if true, the given targets MUST contain EXACTLY ALL given
* tags, AND NO OTHERS. If false, the given targets MUST contain
* ALL given tags, BUT MAY CONTAIN FURTHER ONE
* @param targets targets to be verified
* @param tags are contained within tags of all targets.
*/
private void checkTargetHasTags(final boolean strict, final Iterable<Target> targets, final TargetTag... tags) {
_target:
for (final Target tl : targets) {
for (final Tag tt : getTargetTags(tl.getControllerId())) {
for (final Tag tag : tags) {
if (tag.getName().equals(tt.getName())) {
continue _target;
}
}
if (strict) {
fail("Target does not contain all tags");
}
}
fail("Target does not contain any tags or the expected tag was not found");
}
}
private void checkTargetHasNotTags(final Iterable<Target> targets, final TargetTag... tags) {
for (final Target tl : targets) {
targetManagement.getByControllerID(tl.getControllerId()).get();
for (final Tag tag : tags) {
for (final Tag tt : getTargetTags(tl.getControllerId())) {
if (tag.getName().equals(tt.getName())) {
fail("Target should have no tags");
}
}
}
}
}
private JpaTargetMetadata insertTargetMetadata(final String knownKey, final String knownValue,
final Target target) {
final JpaTargetMetadata metadata = new JpaTargetMetadata(knownKey, knownValue, target);
return (JpaTargetMetadata) targetManagement
.createMetaData(target.getControllerId(), Collections.singletonList(metadata)).get(0);
}
private void checkTargetsHaveType(final List<Target> targets, final TargetType type) {
final List<JpaTarget> foundTargets = targetRepository
.findAllById(targets.stream().map(Identifiable::getId).collect(Collectors.toList()));
for (final Target target : foundTargets) {
if (!type.getName().equals(type.getName())) {
fail(String.format("Target %s is not of type %s.", target, type));
}
}
}
private Target createTargetWithMetadata(final String controllerId, final int count) {
final Target target = testdataFactory.createTarget(controllerId);
for (int index = 1; index <= count; index++) {
insertTargetMetadata("key" + index, controllerId + "-value" + index, target);
}
return target;
}
private Target createTargetWithTargetTypeAndMetadata(final String controllerId, final long targetTypeId, final int count) {
final Target target = testdataFactory.createTarget(controllerId, controllerId, targetTypeId);
for (int index = 1; index <= count; index++) {
insertTargetMetadata("key" + index, controllerId + "-value" + index, target);
}
return target;
}
private void createAction(final Target target, final Rollout rollout, final Integer weight, final Action.Status status,
final DistributionSet distributionSet) {
final JpaAction action = new JpaAction();
action.setActionType(Action.ActionType.FORCED);
action.setTarget(target);
@@ -1437,15 +1446,6 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
actionRepository.save(action);
}
@Test
@Description("Target matches filter for not existing DS.")
void matchesFilterDsNotExists() {
final String target = testdataFactory.createTarget().getControllerId();
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
() -> targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, 123, "name==*"));
}
private void validateFoundTargetsByRsql(final String rsqlFilter, final String... controllerIds) {
final Slice<Target> foundTargetsByMetadataAndControllerId = targetManagement.findByRsql(PAGE, rsqlFilter);
final long foundTargetsByMetadataAndControllerIdCount = targetManagement.countByRsql(rsqlFilter);

View File

@@ -23,6 +23,10 @@ import java.util.stream.Collectors;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
@@ -32,21 +36,13 @@ import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Tag;
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.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.springframework.data.domain.Pageable;
/**
@@ -56,129 +52,8 @@ import org.springframework.data.domain.Pageable;
@Story("Target Tag Management")
class TargetTagManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Verifies that management get access reacts as specfied on calls for non existing entities by means " +
"of Optional not present.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class) })
void nonExistingEntityAccessReturnsNotPresent() {
assertThat(targetTagManagement.getByName(NOT_EXIST_ID)).isNotPresent();
assertThat(targetTagManagement.get(NOT_EXIST_IDL)).isNotPresent();
}
@Test
@Description("Verifies that management queries react as specfied on calls for non existing entities " +
" by means of throwing EntityNotFoundException.")
@ExpectEvents({ @Expect(type = DistributionSetTagUpdatedEvent.class), @Expect(type = TargetTagUpdatedEvent.class) })
void entityQueriesReferringToNotExistingEntitiesThrowsException() {
verifyThrownExceptionBy(() -> targetTagManagement.delete(NOT_EXIST_ID), "TargetTag");
verifyThrownExceptionBy(() -> targetTagManagement.update(entityFactory.tag().update(NOT_EXIST_IDL)), "TargetTag");
verifyThrownExceptionBy(() -> getTargetTags(NOT_EXIST_ID), "Target");
}
@Test
@Description("Verify that a tag with with invalid properties cannot be created or updated")
void createAndUpdateTagWithInvalidFields() {
final TargetTag tag = targetTagManagement.create(entityFactory.tag().create().name("tag1").description("tagdesc1"));
createAndUpdateTagWithInvalidDescription(tag);
createAndUpdateTagWithInvalidColour(tag);
createAndUpdateTagWithInvalidName(tag);
}
@Step
private void createAndUpdateTagWithInvalidDescription(final Tag tag) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long description should not be created")
.isThrownBy(() -> targetTagManagement.create(
entityFactory.tag().create().name("a").description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalid description should not be created").isThrownBy(() -> targetTagManagement
.create(entityFactory.tag().create().name("a").description(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long description should not be updated")
.isThrownBy(() -> targetTagManagement.update(
entityFactory.tag().update(tag.getId())
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalid description should not be updated")
.isThrownBy(() -> targetTagManagement
.update(entityFactory.tag().update(tag.getId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTagWithInvalidColour(final Tag tag) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long colour should not be created")
.isThrownBy(() -> targetTagManagement.create(
entityFactory.tag().create().name("a").colour(RandomStringUtils.randomAlphanumeric(17))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalid colour should not be created").isThrownBy(() -> targetTagManagement
.create(entityFactory.tag().create().name("a").colour(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long colour should not be updated")
.isThrownBy(() -> targetTagManagement.update(
entityFactory.tag().update(tag.getId()).colour(RandomStringUtils.randomAlphanumeric(17))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalid colour should not be updated").isThrownBy(() -> targetTagManagement
.update(entityFactory.tag().update(tag.getId()).colour(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTagWithInvalidName(final Tag tag) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long name should not be created")
.isThrownBy(() -> targetTagManagement
.create(entityFactory.tag().create().name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalidname should not be created")
.isThrownBy(() -> targetTagManagement.create(entityFactory.tag().create().name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long name should not be updated")
.isThrownBy(() -> targetTagManagement
.update(entityFactory.tag().update(tag.getId()).name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class).as("tag with invalid name should not be updated")
.isThrownBy(() -> targetTagManagement
.update(entityFactory.tag().update(tag.getId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too short name should not be updated")
.isThrownBy(() -> targetTagManagement.update(entityFactory.tag().update(tag.getId()).name("")));
}
@Test
@Description("Verifies assign/unassign.")
void assignAndUnassignTargetTags() {
final List<Target> groupA = testdataFactory.createTargets(20);
final List<Target> groupB = testdataFactory.createTargets(20, "groupb", "groupb");
final TargetTag tag = targetTagManagement.create(entityFactory.tag().create().name("tag1").description("tagdesc1"));
// toggle A only -> A is now assigned
List<Target> result = assignTag(groupA, tag);
assertThat(result).size().isEqualTo(20);
assertThat(result).containsAll(
targetManagement.getByControllerID(groupA.stream().map(Target::getControllerId).collect(Collectors.toList())));
assertThat(targetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent().stream().map(Target::getControllerId).sorted().toList())
.isEqualTo(groupA.stream().map(Target::getControllerId).sorted().toList());
// toggle A+B -> A is still assigned and B is assigned as well
final Collection<Target> groupAB = concat(groupA, groupB);
result = assignTag(groupAB, tag);
assertThat(result).size().isEqualTo(40);
assertThat(result).containsAll(
targetManagement.getByControllerID(groupAB.stream().map(Target::getControllerId).collect(Collectors.toList())));
assertThat(targetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent().stream().map(Target::getControllerId).sorted().toList())
.isEqualTo(groupAB.stream().map(Target::getControllerId).sorted().toList());
// toggle A+B -> both unassigned
result = unassignTag(groupAB, tag);
assertThat(result).size().isEqualTo(40);
assertThat(result).containsAll(
targetManagement.getByControllerID(groupAB.stream().map(Target::getControllerId).collect(Collectors.toList())));
assertThat(targetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent()).isEmpty();
}
private static final Random RND = new Random();
@Test
@Description("Verifies that tagging of set containing missing DS throws meaningful and correct exception.")
public void failOnMissingDs() {
@@ -212,11 +87,67 @@ class TargetTagManagementTest extends AbstractJpaIntegrationTest {
});
}
@SafeVarargs
private <T> Collection<T> concat(final Collection<T>... targets) {
final List<T> result = new ArrayList<>();
Arrays.asList(targets).forEach(result::addAll);
return result;
@Test
@Description("Verifies that management get access reacts as specfied on calls for non existing entities by means " +
"of Optional not present.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class) })
void nonExistingEntityAccessReturnsNotPresent() {
assertThat(targetTagManagement.getByName(NOT_EXIST_ID)).isNotPresent();
assertThat(targetTagManagement.get(NOT_EXIST_IDL)).isNotPresent();
}
@Test
@Description("Verifies that management queries react as specfied on calls for non existing entities " +
" by means of throwing EntityNotFoundException.")
@ExpectEvents({ @Expect(type = DistributionSetTagUpdatedEvent.class), @Expect(type = TargetTagUpdatedEvent.class) })
void entityQueriesReferringToNotExistingEntitiesThrowsException() {
verifyThrownExceptionBy(() -> targetTagManagement.delete(NOT_EXIST_ID), "TargetTag");
verifyThrownExceptionBy(() -> targetTagManagement.update(entityFactory.tag().update(NOT_EXIST_IDL)), "TargetTag");
verifyThrownExceptionBy(() -> getTargetTags(NOT_EXIST_ID), "Target");
}
@Test
@Description("Verify that a tag with with invalid properties cannot be created or updated")
void createAndUpdateTagWithInvalidFields() {
final TargetTag tag = targetTagManagement.create(entityFactory.tag().create().name("tag1").description("tagdesc1"));
createAndUpdateTagWithInvalidDescription(tag);
createAndUpdateTagWithInvalidColour(tag);
createAndUpdateTagWithInvalidName(tag);
}
@Test
@Description("Verifies assign/unassign.")
void assignAndUnassignTargetTags() {
final List<Target> groupA = testdataFactory.createTargets(20);
final List<Target> groupB = testdataFactory.createTargets(20, "groupb", "groupb");
final TargetTag tag = targetTagManagement.create(entityFactory.tag().create().name("tag1").description("tagdesc1"));
// toggle A only -> A is now assigned
List<Target> result = assignTag(groupA, tag);
assertThat(result).size().isEqualTo(20);
assertThat(result).containsAll(
targetManagement.getByControllerID(groupA.stream().map(Target::getControllerId).collect(Collectors.toList())));
assertThat(targetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent().stream().map(Target::getControllerId).sorted()
.toList())
.isEqualTo(groupA.stream().map(Target::getControllerId).sorted().toList());
// toggle A+B -> A is still assigned and B is assigned as well
final Collection<Target> groupAB = concat(groupA, groupB);
result = assignTag(groupAB, tag);
assertThat(result).size().isEqualTo(40);
assertThat(result).containsAll(
targetManagement.getByControllerID(groupAB.stream().map(Target::getControllerId).collect(Collectors.toList())));
assertThat(targetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent().stream().map(Target::getControllerId).sorted()
.toList())
.isEqualTo(groupAB.stream().map(Target::getControllerId).sorted().toList());
// toggle A+B -> both unassigned
result = unassignTag(groupAB, tag);
assertThat(result).size().isEqualTo(40);
assertThat(result).containsAll(
targetManagement.getByControllerID(groupAB.stream().map(Target::getControllerId).collect(Collectors.toList())));
assertThat(targetManagement.findByTag(Pageable.unpaged(), tag.getId()).getContent()).isEmpty();
}
@Test
@@ -302,6 +233,74 @@ class TargetTagManagementTest extends AbstractJpaIntegrationTest {
.isThrownBy(() -> targetTagManagement.update(entityFactory.tag().update(tag.getId()).name("A")));
}
@Step
private void createAndUpdateTagWithInvalidDescription(final Tag tag) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long description should not be created")
.isThrownBy(() -> targetTagManagement.create(
entityFactory.tag().create().name("a").description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalid description should not be created").isThrownBy(() -> targetTagManagement
.create(entityFactory.tag().create().name("a").description(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long description should not be updated")
.isThrownBy(() -> targetTagManagement.update(
entityFactory.tag().update(tag.getId())
.description(RandomStringUtils.randomAlphanumeric(513))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalid description should not be updated")
.isThrownBy(() -> targetTagManagement
.update(entityFactory.tag().update(tag.getId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTagWithInvalidColour(final Tag tag) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long colour should not be created")
.isThrownBy(() -> targetTagManagement.create(
entityFactory.tag().create().name("a").colour(RandomStringUtils.randomAlphanumeric(17))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalid colour should not be created").isThrownBy(() -> targetTagManagement
.create(entityFactory.tag().create().name("a").colour(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long colour should not be updated")
.isThrownBy(() -> targetTagManagement.update(
entityFactory.tag().update(tag.getId()).colour(RandomStringUtils.randomAlphanumeric(17))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalid colour should not be updated").isThrownBy(() -> targetTagManagement
.update(entityFactory.tag().update(tag.getId()).colour(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTagWithInvalidName(final Tag tag) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long name should not be created")
.isThrownBy(() -> targetTagManagement
.create(entityFactory.tag().create().name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with invalidname should not be created")
.isThrownBy(() -> targetTagManagement.create(entityFactory.tag().create().name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too long name should not be updated")
.isThrownBy(() -> targetTagManagement
.update(entityFactory.tag().update(tag.getId()).name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class).as("tag with invalid name should not be updated")
.isThrownBy(() -> targetTagManagement
.update(entityFactory.tag().update(tag.getId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("tag with too short name should not be updated")
.isThrownBy(() -> targetTagManagement.update(entityFactory.tag().update(tag.getId()).name("")));
}
@SafeVarargs
private <T> Collection<T> concat(final Collection<T>... targets) {
final List<T> result = new ArrayList<>();
Arrays.asList(targets).forEach(result::addAll);
return result;
}
private List<JpaTargetTag> createTargetsWithTags() {
final List<Target> targets = testdataFactory.createTargets(20);
final Iterable<TargetTag> tags = testdataFactory.createTargetTags(20, "");

View File

@@ -18,6 +18,10 @@ import java.util.Optional;
import jakarta.validation.ConstraintViolationException;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
@@ -32,11 +36,6 @@ import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Target Type Management")
class TargetTypeManagementTest extends AbstractJpaIntegrationTest {
@@ -98,70 +97,6 @@ class TargetTypeManagementTest extends AbstractJpaIntegrationTest {
.update(entityFactory.targetType().update(targetType.getId()).description(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTargetTypeWithInvalidColour(final TargetType targetType) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long colour should not be created")
.isThrownBy(() -> targetTypeManagement.create(
entityFactory.targetType().create().name("a")
.colour(RandomStringUtils.randomAlphanumeric(TargetType.COLOUR_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid colour should not be created").isThrownBy(() -> targetTypeManagement
.create(entityFactory.targetType().create().name("a").colour(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long colour should not be updated")
.isThrownBy(() -> targetTypeManagement.update(
entityFactory.targetType().update(targetType.getId())
.colour(RandomStringUtils.randomAlphanumeric(TargetType.COLOUR_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid colour should not be updated").isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).colour(INVALID_TEXT_HTML)));
}
@Step
private void createTargetTypeWithInvalidKey() {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long key should not be created")
.isThrownBy(() -> targetTypeManagement
.create(entityFactory.targetType().create().name(RandomStringUtils.randomAlphanumeric(
Type.KEY_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid key should not be created").isThrownBy(
() -> targetTypeManagement.create(entityFactory.targetType().create().name(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTargetTypeWithInvalidName(final TargetType targetType) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long name should not be created")
.isThrownBy(() -> targetTypeManagement
.create(entityFactory.targetType().create().name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid name should not be created").isThrownBy(
() -> targetTypeManagement.create(entityFactory.targetType().create().name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long name should not be updated")
.isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid name should not be updated").isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too short name should not be updated").isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).name("")));
}
@Test
@Description("Tests the successful assignment of compatible distribution set types to a target type")
void assignCompatibleDistributionSetTypesToTargetType() {
@@ -189,7 +124,7 @@ class TargetTypeManagementTest extends AbstractJpaIntegrationTest {
Optional<JpaTargetType> targetTypeWithDsTypes = targetTypeRepository.findById(targetType.getId());
assertThat(targetTypeWithDsTypes).isPresent();
assertThat(targetTypeWithDsTypes.get().getCompatibleDistributionSetTypes()).extracting("key").contains("testDst1");
targetTypeManagement.unassignDistributionSetType(targetType.getId(),distributionSetType.getId());
targetTypeManagement.unassignDistributionSetType(targetType.getId(), distributionSetType.getId());
Optional<JpaTargetType> targetTypeWithDsTypes1 = targetTypeRepository.findById(targetType.getId());
assertThat(targetTypeWithDsTypes1).isPresent();
assertThat(targetTypeWithDsTypes1.get().getCompatibleDistributionSetTypes()).isEmpty();
@@ -260,7 +195,8 @@ class TargetTypeManagementTest extends AbstractJpaIntegrationTest {
@Description("Ensures that a target type cannot be created if one exists already with that name (expects EntityAlreadyExistsException).")
void failedDuplicateTargetTypeNameException() {
targetTypeManagement.create(entityFactory.targetType().create().name("targettype123"));
assertThrows(EntityAlreadyExistsException.class, () -> targetTypeManagement.create(entityFactory.targetType().create().name("targettype123")));
assertThrows(EntityAlreadyExistsException.class,
() -> targetTypeManagement.create(entityFactory.targetType().create().name("targettype123")));
}
@Test
@@ -268,7 +204,72 @@ class TargetTypeManagementTest extends AbstractJpaIntegrationTest {
void failedDuplicateTargetTypeNameExceptionAfterUpdate() {
targetTypeManagement.create(entityFactory.targetType().create().name("targettype1234"));
TargetType targetType = targetTypeManagement.create(entityFactory.targetType().create().name("targettype12345"));
assertThrows(EntityAlreadyExistsException.class, () -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name("targettype1234")));
assertThrows(EntityAlreadyExistsException.class,
() -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name("targettype1234")));
}
@Step
private void createAndUpdateTargetTypeWithInvalidColour(final TargetType targetType) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long colour should not be created")
.isThrownBy(() -> targetTypeManagement.create(
entityFactory.targetType().create().name("a")
.colour(RandomStringUtils.randomAlphanumeric(TargetType.COLOUR_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid colour should not be created").isThrownBy(() -> targetTypeManagement
.create(entityFactory.targetType().create().name("a").colour(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long colour should not be updated")
.isThrownBy(() -> targetTypeManagement.update(
entityFactory.targetType().update(targetType.getId())
.colour(RandomStringUtils.randomAlphanumeric(TargetType.COLOUR_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid colour should not be updated").isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).colour(INVALID_TEXT_HTML)));
}
@Step
private void createTargetTypeWithInvalidKey() {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long key should not be created")
.isThrownBy(() -> targetTypeManagement
.create(entityFactory.targetType().create().name(RandomStringUtils.randomAlphanumeric(
Type.KEY_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid key should not be created").isThrownBy(
() -> targetTypeManagement.create(entityFactory.targetType().create().name(INVALID_TEXT_HTML)));
}
@Step
private void createAndUpdateTargetTypeWithInvalidName(final TargetType targetType) {
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long name should not be created")
.isThrownBy(() -> targetTypeManagement
.create(entityFactory.targetType().create().name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid name should not be created").isThrownBy(
() -> targetTypeManagement.create(entityFactory.targetType().create().name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too long name should not be updated")
.isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with invalid name should not be updated").isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).name(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("targetType with too short name should not be updated").isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).name("")));
}
private Optional<JpaTargetType> findByName(final String name) {

View File

@@ -17,6 +17,9 @@ import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.exception.InvalidTenantConfigurationKeyException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
@@ -28,10 +31,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Tenant Configuration Management")
public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest implements EnvironmentAware {
@@ -101,9 +100,11 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes
// add value first
tenantConfigurationManagement.addOrUpdateConfiguration(configuration);
assertThat(tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue())
assertThat(tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY,
String.class).getValue())
.isEqualTo("token_123");
assertThat(tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue())
assertThat(
tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue())
.isTrue();
}
@@ -149,9 +150,12 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes
tenantConfigurationManagement.addOrUpdateConfiguration(configuration);
fail("should not have worked as type is wrong");
} catch (final TenantConfigurationValidatorException e) {
assertThat(tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue())
assertThat(
tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY,
String.class).getValue())
.isNotEqualTo("token_123");
assertThat(tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue())
assertThat(tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class)
.getValue())
.isNotEqualTo(true);
}
}

View File

@@ -11,15 +11,14 @@ package org.eclipse.hawkbit.repository.jpa.model;
import static org.assertj.core.api.Assertions.assertThat;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.EntityInterceptor;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@@ -131,6 +130,7 @@ public class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
}
private static class PrePersistEntityListener extends AbstractEntityListener {
@Override
public void prePersist(final Object entity) {
setEntity(entity);
@@ -138,6 +138,7 @@ public class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
}
private static class PostPersistEntityListener extends AbstractEntityListener {
@Override
public void postPersist(final Object entity) {
setEntity(entity);
@@ -146,6 +147,7 @@ public class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
}
private static class PostLoadEntityListener extends AbstractEntityListener {
@Override
public void postLoad(final Object entity) {
setEntity(entity);
@@ -154,6 +156,7 @@ public class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
}
private static class PreUpdateEntityListener extends AbstractEntityListener {
@Override
public void preUpdate(final Object entity) {
setEntity(entity);
@@ -161,6 +164,7 @@ public class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
}
private static class PostUpdateEntityListener extends AbstractEntityListener {
@Override
public void postUpdate(final Object entity) {
setEntity(entity);
@@ -168,6 +172,7 @@ public class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
}
private static class PreRemoveEntityListener extends AbstractEntityListener {
@Override
public void preRemove(final Object entity) {
setEntity(entity);
@@ -175,6 +180,7 @@ public class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
}
private static class PostRemoveEntityListener extends AbstractEntityListener {
@Override
public void postRemove(final Object entity) {
setEntity(entity);

View File

@@ -11,13 +11,12 @@ package org.eclipse.hawkbit.repository.jpa.model;
import static org.assertj.core.api.Assertions.assertThat;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.junit.jupiter.api.Test;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.junit.jupiter.api.Test;
@Feature("Unit Tests - Repository")
@Story("Repository Model")

View File

@@ -12,6 +12,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.ActionFields;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -28,10 +31,6 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.orm.jpa.vendor.Database;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter actions")
public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
@@ -51,25 +50,6 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
}
}
private @NotNull JpaAction newJpaAction(final DistributionSet dsA, final boolean active, final String extRef) {
final JpaAction newAction = new JpaAction();
newAction.setActionType(ActionType.SOFT);
newAction.setDistributionSet(dsA);
newAction.setActive(active);
newAction.setStatus(Status.RUNNING);
newAction.setTarget(target);
newAction.setWeight(45);
newAction.setInitiatedBy(tenantAware.getCurrentUsername());
if (extRef != null) {
newAction.setExternalRef(extRef);
}
actionRepository.save(newAction);
target.addAction(action);
return newAction;
}
@Test
@Description("Test filter action by id")
public void testFilterByParameterId() {
@@ -104,6 +84,7 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
}
}
@Test
@Description("Test action by status")
public void testFilterByParameterExtRef() {
@@ -112,6 +93,25 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(ActionFields.EXTERNALREF.name() + "==extRef*", 10);
}
private @NotNull JpaAction newJpaAction(final DistributionSet dsA, final boolean active, final String extRef) {
final JpaAction newAction = new JpaAction();
newAction.setActionType(ActionType.SOFT);
newAction.setDistributionSet(dsA);
newAction.setActive(active);
newAction.setStatus(Status.RUNNING);
newAction.setTarget(target);
newAction.setWeight(45);
newAction.setInitiatedBy(tenantAware.getCurrentUsername());
if (extRef != null) {
newAction.setExternalRef(extRef);
}
actionRepository.save(newAction);
target.addAction(action);
return newAction;
}
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
final Slice<Action> findEntity = deploymentManagement.findActionsByTarget(rsqlParam, target.getControllerId(),
PageRequest.of(0, 100));

View File

@@ -16,6 +16,9 @@ import static org.junit.jupiter.api.Assertions.fail;
import java.util.Arrays;
import java.util.Collections;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.DistributionSetFields;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
@@ -31,10 +34,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.orm.jpa.vendor.Database;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter distribution set")
public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
@@ -47,7 +46,7 @@ public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
sm = testdataFactory.createSoftwareModuleApp("SM");
ds = testdataFactory.createDistributionSet(Collections.singletonList(sm),"DS");
ds = testdataFactory.createDistributionSet(Collections.singletonList(sm), "DS");
ds = distributionSetManagement.update(entityFactory.distributionSet().update(ds.getId()).description("DS"));
createDistributionSetMetadata(ds.getId(), entityFactory.generateDsMetadata("metaKey", "metaValue"));

View File

@@ -15,6 +15,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.DistributionSetMetadataFields;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -25,10 +28,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter distribution set metadata")
public class RSQLDistributionSetMetadataFieldsTest extends AbstractJpaIntegrationTest {

View File

@@ -15,31 +15,28 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle;
import org.eclipse.hawkbit.repository.rsql.SuggestToken;
import org.eclipse.hawkbit.repository.rsql.ValidationOracleContext;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter suggestion")
public class RSQLParserValidationOracleTest extends AbstractJpaIntegrationTest {
@Autowired
private RsqlValidationOracle rsqlValidationOracle;
private static final String[] OP_SUGGESTIONS = new String[] { "==", "!=", "=ge=", "=le=", "=gt=", "=lt=", "=in=",
"=out=" };
private static final String[] FIELD_SUGGESTIONS = Arrays.stream(TargetFields.values())
.map(field -> field.name().toLowerCase()).toArray(String[]::new);
private static final String[] AND_OR_SUGGESTIONS = new String[] { "and", "or" };
private static final String[] NAME_VERSION_SUGGESTIONS = new String[] { "name", "version" };
@Autowired
private RsqlValidationOracle rsqlValidationOracle;
@Test
@Description("Verifies that suggestions contains all possible field names")

View File

@@ -11,6 +11,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.RolloutGroupFields;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -24,10 +27,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.orm.jpa.vendor.Database;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter rollout group")
public class RSQLRolloutGroupFieldTest extends AbstractJpaIntegrationTest {

View File

@@ -11,6 +11,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -18,16 +21,11 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.orm.jpa.vendor.Database;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter software module")
public class RSQLSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {

View File

@@ -14,6 +14,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -25,10 +28,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter software module metadata")
public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractJpaIntegrationTest {

View File

@@ -11,6 +11,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.Constants;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -20,10 +23,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.orm.jpa.vendor.Database;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter software module test type")
public class RSQLSoftwareModuleTypeFieldsTest extends AbstractJpaIntegrationTest {

View File

@@ -11,6 +11,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.TagFields;
import org.eclipse.hawkbit.repository.builder.TagCreate;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -21,10 +24,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter target and distribution set tags")
public class RSQLTagFieldsTest extends AbstractJpaIntegrationTest {

View File

@@ -17,6 +17,9 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.assertj.core.util.Maps;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TargetTypeFields;
@@ -31,22 +34,17 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Slice;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter target")
class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
private static final String OR = ",";
private static final String AND = ";";
private Target target;
private Target target2;
private TargetType targetType1;
private TargetType targetType2;
private static final String OR = ",";
private static final String AND = ";";
@BeforeEach
void setupBeforeTest() {

View File

@@ -12,6 +12,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -23,10 +26,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.orm.jpa.vendor.Database;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter target filter query")
public class RSQLTargetFilterQueryFieldsTest extends AbstractJpaIntegrationTest {

View File

@@ -15,6 +15,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.TargetMetadataFields;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.MetaData;
@@ -25,13 +28,10 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("RSQL filter target metadata")
public class RSQLTargetMetadataFieldsTest extends AbstractJpaIntegrationTest {
private String controllerId;
@BeforeEach

View File

@@ -13,12 +13,14 @@ import cz.jirutka.rsql.parser.RSQLParser;
import cz.jirutka.rsql.parser.ast.Node;
import cz.jirutka.rsql.parser.ast.RSQLOperators;
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
@@ -39,11 +41,13 @@ public class RSQLToSQL {
this.entityManager = entityManager;
}
public <T, A extends Enum<A> & RsqlQueryField> String toSQL(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
public <T, A extends Enum<A> & RsqlQueryField> String toSQL(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql,
final boolean legacyRsqlVisitor) {
return createDbQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor).getSQLString();
}
public <T, A extends Enum<A> & RsqlQueryField> DatabaseQuery createDbQuery(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
public <T, A extends Enum<A> & RsqlQueryField> DatabaseQuery createDbQuery(final Class<T> domainClass, final Class<A> fieldsClass,
final String rsql, final boolean legacyRsqlVisitor) {
final CriteriaQuery<T> query = createQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor);
final TypedQuery<?> typedQuery = entityManager.createQuery(query);
// executes the query - otherwise the SQL string is not generated
@@ -52,13 +56,14 @@ public class RSQLToSQL {
return typedQuery.unwrap(JpaQuery.class).getDatabaseQuery();
}
private <T, A extends Enum<A> & RsqlQueryField> CriteriaQuery<T> createQuery(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
private <T, A extends Enum<A> & RsqlQueryField> CriteriaQuery<T> createQuery(final Class<T> domainClass, final Class<A> fieldsClass,
final String rsql, final boolean legacyRsqlVisitor) {
final CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
return query.where(
RsqlConfigHolder.getInstance().isLegacyRsqlVisitor() == legacyRsqlVisitor ?
// use directly
RSQLUtility.<A, T>buildRsqlSpecification(rsql, fieldsClass, null, DATABASE)
RSQLUtility.<A, T> buildRsqlSpecification(rsql, fieldsClass, null, DATABASE)
.toPredicate(query.from(domainClass), cb.createQuery(domainClass), cb) :
toPredicate(rsql, fieldsClass, null,
query.from(domainClass), cb.createQuery(domainClass), cb, legacyRsqlVisitor)
@@ -80,10 +85,10 @@ public class RSQLToSQL {
virtualPropertyReplacer, DATABASE, query,
!RsqlConfigHolder.getInstance().isCaseInsensitiveDB() && RsqlConfigHolder.getInstance().isIgnoreCase())
:
new JpaQueryRsqlVisitorG2<>(
fieldsClass, root, query, cb,
DATABASE, virtualPropertyReplacer,
!RsqlConfigHolder.getInstance().isCaseInsensitiveDB() && RsqlConfigHolder.getInstance().isIgnoreCase());
new JpaQueryRsqlVisitorG2<>(
fieldsClass, root, query, cb,
DATABASE, virtualPropertyReplacer,
!RsqlConfigHolder.getInstance().isCaseInsensitiveDB() && RsqlConfigHolder.getInstance().isIgnoreCase());
final List<Predicate> accept = rootNode.accept(jpqQueryRSQLVisitor);
if (CollectionUtils.isEmpty(accept)) {

View File

@@ -9,8 +9,11 @@
*/
package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
@@ -24,10 +27,8 @@ import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
@ActiveProfiles("test")
@SpringBootTest(webEnvironment=NONE, properties = {
@SpringBootTest(webEnvironment = NONE, properties = {
"hawkbit.rsql.caseInsensitiveDB=true",
"spring.main.allow-bean-definition-overriding=true",
"spring.main.banner-mode=off",
@@ -39,11 +40,6 @@ public class RSQLToSQLTest {
private RSQLToSQL rsqlToSQL;
@PersistenceContext
private void setEntityManager(final EntityManager entityManager) {
rsqlToSQL = new RSQLToSQL(entityManager);
}
@Test
public void print() {
print(JpaTarget.class, TargetFields.class, "tag==tag1 and tag==tag2");
@@ -58,6 +54,15 @@ public class RSQLToSQLTest {
printFrom(JpaTarget.class, TargetFields.class, "tag==TAG1 and tag!=TAG2");
}
private static String from(final String sql) {
return sql.substring(sql.indexOf("FROM"));
}
@PersistenceContext
private void setEntityManager(final EntityManager entityManager) {
rsqlToSQL = new RSQLToSQL(entityManager);
}
private <T, A extends Enum<A> & RsqlQueryField> void print(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
System.out.println(rsql);
System.out.println("\tlegacy:\n" +
@@ -73,7 +78,4 @@ public class RSQLToSQLTest {
System.out.println("\tG2:\n" +
"\t\t" + from(rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, false)));
}
private static String from(final String sql) {
return sql.substring(sql.indexOf("FROM"));
}
}

View File

@@ -33,10 +33,13 @@ import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.Type;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.DistributionSetFields;
import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
@@ -48,8 +51,8 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.rsql.RsqlVisitorFactory;
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
import org.eclipse.hawkbit.repository.rsql.RsqlVisitorFactory;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
import org.eclipse.hawkbit.security.SystemSecurityContext;
@@ -66,10 +69,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@ExtendWith(SpringExtension.class)
@Feature("Component Tests - Repository")
@Story("RSQL search utility")
@@ -77,58 +76,31 @@ import io.qameta.allure.Story;
// method name as short text
public class RSQLUtilityTest {
@Spy
private final VirtualPropertyResolver macroResolver = new VirtualPropertyResolver();
@MockBean
private TenantConfigurationManagement confMgmt;
@MockBean
private SystemSecurityContext securityContext;
@MockBean
private RsqlVisitorFactory rsqlVisitorFactory;
@Mock
private Root<Object> baseSoftwareModuleRootMock;
@Mock
private CriteriaQuery<SoftwareModule> criteriaQueryMock;
@Mock
private CriteriaBuilder criteriaBuilderMock;
@Mock
private Subquery<SoftwareModule> subqueryMock;
@Mock
private Root<SoftwareModule> subqueryRootMock;
private final Database testDb = Database.H2;
@Mock
private Attribute attribute;
@Configuration
static class Config {
@Bean
TenantConfigurationManagementHolder tenantConfigurationManagementHolder() {
return TenantConfigurationManagementHolder.getInstance();
}
@Bean
SystemSecurityContextHolder systemSecurityContextHolder() {
return SystemSecurityContextHolder.getInstance();
}
@Bean
RsqlConfigHolder rsqlVisitorFactoryHolder() {
return RsqlConfigHolder.getInstance();
}
}
private static final TenantConfigurationValue<String> TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue
.<String> builder().value("00:05:00").build();
private static final TenantConfigurationValue<String> TEST_POLLING_OVERDUE_TIME_INTERVAL = TenantConfigurationValue
.<String> builder().value("00:07:37").build();
@Spy
private final VirtualPropertyResolver macroResolver = new VirtualPropertyResolver();
private final Database testDb = Database.H2;
@MockBean
private TenantConfigurationManagement confMgmt;
@MockBean
private SystemSecurityContext securityContext;
@MockBean
private RsqlVisitorFactory rsqlVisitorFactory;
@Mock
private Root<Object> baseSoftwareModuleRootMock;
@Mock
private CriteriaQuery<SoftwareModule> criteriaQueryMock;
@Mock
private CriteriaBuilder criteriaBuilderMock;
@Mock
private Subquery<SoftwareModule> subqueryMock;
@Mock
private Root<SoftwareModule> subqueryRootMock;
@Mock
private Attribute attribute;
@BeforeEach
public void beforeEach() {
@@ -555,6 +527,34 @@ public class RSQLUtilityTest {
return (Path<Y>) path;
}
private void validateRsqlForTestFields(final String rsql) {
when(rsqlVisitorFactory.validationRsqlVisitor(eq(TestFieldEnum.class))).thenReturn(
new FieldValidationRsqlVisitor<>(TestFieldEnum.class));
RSQLUtility.validateRsqlFor(rsql, TestFieldEnum.class);
}
private void reset0(final Object... mocks) {
reset(mocks);
if (Arrays.asList(mocks).contains(baseSoftwareModuleRootMock)) {
setupRoot(baseSoftwareModuleRootMock);
}
if (Arrays.asList(mocks).contains(subqueryRootMock)) {
setupRoot(subqueryRootMock);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void setupRoot(final Root<?> root) {
final Type type = Mockito.mock(Type.class);
when(type.getPersistenceType()).thenReturn(Type.PersistenceType.BASIC);
final SingularAttribute singularAttribute = Mockito.mock(SingularAttribute.class);
when(singularAttribute.getType()).thenReturn(type);
final EntityType entityType = Mockito.mock(EntityType.class);
when(entityType.getAttribute(any())).thenReturn(singularAttribute);
when(entityType.getPersistenceType()).thenReturn(Type.PersistenceType.BASIC);
when(root.getModel()).thenReturn(entityType);
}
private enum TestFieldEnum implements RsqlQueryField {
TESTFIELD("testfield"), TESTFIELD_WITH_SUB_ENTITIES("testfieldWithSubEntities", "subentity11", "subentity22");
@@ -581,34 +581,26 @@ public class RSQLUtilityTest {
}
}
private void validateRsqlForTestFields(final String rsql) {
when(rsqlVisitorFactory.validationRsqlVisitor(eq(TestFieldEnum.class))).thenReturn(new FieldValidationRsqlVisitor<>(TestFieldEnum.class));
RSQLUtility.validateRsqlFor(rsql, TestFieldEnum.class);
}
private void reset0(final Object... mocks) {
reset(mocks);
if (Arrays.asList(mocks).contains(baseSoftwareModuleRootMock)) {
setupRoot(baseSoftwareModuleRootMock);
}
if (Arrays.asList(mocks).contains(subqueryRootMock)) {
setupRoot(subqueryRootMock);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void setupRoot(final Root<?> root) {
final Type type = Mockito.mock(Type.class);
when(type.getPersistenceType()).thenReturn(Type.PersistenceType.BASIC);
final SingularAttribute singularAttribute = Mockito.mock(SingularAttribute.class);
when(singularAttribute.getType()).thenReturn(type);
final EntityType entityType = Mockito.mock(EntityType.class);
when(entityType.getAttribute(any())).thenReturn(singularAttribute);
when(entityType.getPersistenceType()).thenReturn(Type.PersistenceType.BASIC);
when(root.getModel()).thenReturn(entityType);
}
private enum TestValueEnum {
BUMLUX;
}
@Configuration
static class Config {
@Bean
TenantConfigurationManagementHolder tenantConfigurationManagementHolder() {
return TenantConfigurationManagementHolder.getInstance();
}
@Bean
SystemSecurityContextHolder systemSecurityContextHolder() {
return SystemSecurityContextHolder.getInstance();
}
@Bean
RsqlConfigHolder rsqlVisitorFactoryHolder() {
return RsqlConfigHolder.getInstance();
}
}
}

View File

@@ -14,6 +14,9 @@ import static org.mockito.Mockito.when;
import java.util.concurrent.Callable;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
@@ -34,43 +37,22 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@ExtendWith(SpringExtension.class)
@Feature("Unit Tests - Repository")
@Story("Placeholder resolution for virtual properties")
public class VirtualPropertyResolverTest {
@Spy
private final VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver();
@MockBean
private TenantConfigurationManagement confMgmt;
@MockBean
private SystemSecurityContext securityContext;
private StrSubstitutor substitutor;
private static final TenantConfigurationValue<String> TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue
.<String> builder().value("00:05:00").build();
private static final TenantConfigurationValue<String> TEST_POLLING_OVERDUE_TIME_INTERVAL = TenantConfigurationValue
.<String> builder().value("00:07:37").build();
@Configuration
static class Config {
@Bean
TenantConfigurationManagementHolder tenantConfigurationManagementHolder() {
return TenantConfigurationManagementHolder.getInstance();
}
@Bean
SystemSecurityContextHolder systemSecurityContextHolder() {
return SystemSecurityContextHolder.getInstance();
}
}
@Spy
private final VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver();
@MockBean
private TenantConfigurationManagement confMgmt;
@MockBean
private SystemSecurityContext securityContext;
private StrSubstitutor substitutor;
@BeforeEach
public void before() {
@@ -83,18 +65,6 @@ public class VirtualPropertyResolverTest {
StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE);
}
@ParameterizedTest
@ValueSource(strings = { "${NOW_TS}", "${OVERDUE_TS}", "${overdue_ts}" })
@Description("Tests resolution of NOW_TS by using a StrSubstitutor configured with the VirtualPropertyResolver.")
void resolveNowTimestampPlaceholder(final String placeholder) {
when(securityContext.runAsSystem(Mockito.any())).thenAnswer(a -> ((Callable<?>) a.getArgument(0)).call());
final String testString = "lhs=lt=" + placeholder;
final String resolvedPlaceholders = substitutor.replace(testString);
assertThat(resolvedPlaceholders).as("'%s' placeholder was not replaced", placeholder)
.doesNotContain(placeholder);
}
@Test
@Description("Tests VirtualPropertyResolver with a placeholder unknown to VirtualPropertyResolver.")
public void handleUnknownPlaceholder() {
@@ -115,4 +85,30 @@ public class VirtualPropertyResolverTest {
final String resolvedPlaceholders = substitutor.replace(testString);
assertThat(resolvedPlaceholders).as("Escaped OVERDUE_TS should not be resolved!").contains(placeholder);
}
@ParameterizedTest
@ValueSource(strings = { "${NOW_TS}", "${OVERDUE_TS}", "${overdue_ts}" })
@Description("Tests resolution of NOW_TS by using a StrSubstitutor configured with the VirtualPropertyResolver.")
void resolveNowTimestampPlaceholder(final String placeholder) {
when(securityContext.runAsSystem(Mockito.any())).thenAnswer(a -> ((Callable<?>) a.getArgument(0)).call());
final String testString = "lhs=lt=" + placeholder;
final String resolvedPlaceholders = substitutor.replace(testString);
assertThat(resolvedPlaceholders).as("'%s' placeholder was not replaced", placeholder)
.doesNotContain(placeholder);
}
@Configuration
static class Config {
@Bean
TenantConfigurationManagementHolder tenantConfigurationManagementHolder() {
return TenantConfigurationManagementHolder.getInstance();
}
@Bean
SystemSecurityContextHolder systemSecurityContextHolder() {
return SystemSecurityContextHolder.getInstance();
}
}
}

View File

@@ -27,12 +27,11 @@ import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.junit.jupiter.api.Test;
import org.springframework.data.jpa.domain.Specification;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.junit.jupiter.api.Test;
import org.springframework.data.jpa.domain.Specification;
@Feature("Unit Tests - Repository")
@Story("Specifications builder")

View File

@@ -16,6 +16,9 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Callable;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -27,15 +30,10 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.data.domain.Slice;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Multi-Tenancy tests which testing the CRUD operations of entities that all
* CRUD-Operations are tenant aware and cannot access or delete entities not
* belonging to the current tenant.
*
*/
@Feature("Component Tests - Repository")
@Story("Multi Tenancy")
@@ -110,7 +108,7 @@ public class MultiTenancyEntityTest extends AbstractJpaIntegrationTest {
// autogenerated
assertThat(distributionSetTypeManagement.findAll(PAGE)).isEmpty();
SecurityContextSwitch.runAsPrivileged(() ->
assertThat(systemManagement.createTenantMetadata("mytenant").getTenant().toUpperCase()).isEqualTo("mytenant".toUpperCase()));
assertThat(systemManagement.createTenantMetadata("mytenant").getTenant().toUpperCase()).isEqualTo("mytenant".toUpperCase()));
assertThat(distributionSetTypeManagement.findAll(PAGE)).isNotEmpty();
@@ -119,7 +117,7 @@ public class MultiTenancyEntityTest extends AbstractJpaIntegrationTest {
// mytenant
assertThat(SecurityContextSwitch.runAs(SecurityContextSwitch.withUserAndTenantAllSpPermissions("user", "bumlux"),
() -> systemManagement.getTenantMetadata().getTenant().toUpperCase()))
.isEqualTo("bumlux".toUpperCase());
.isEqualTo("bumlux".toUpperCase());
}
@Test

View File

@@ -7,7 +7,6 @@
#
# SPDX-License-Identifier: EPL-2.0
#
# Debug utility functions - START
logging.level.org.eclipse.persistence=ERROR
#incomment to see the debug of persistence, e.g. to see the generated SQLs
@@ -16,6 +15,5 @@ spring.jpa.properties.eclipselink.logging.level=FINE
spring.jpa.properties.eclipselink.logging.level.sql=FINE
spring.jpa.properties.eclipselink.logging.parameters=true
# Debug utility functions - END
# enable / disable case sensitiveness of the DB when playing around
#hawkbit.rsql.caseInsensitiveDB=true