Feature/ctx aware and access controller2 (#1456)
* Introduce the AccessControlManager and use if for the TargetManagement and TargetTypeManagement. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Extend the access control manager by an API to serialize the current active context and persist it for scheduled background operations like auto-assignment. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Verify modification is permitted before performing automatic assignment Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Start with controlling distribution set type access. Perform some refactoring. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Support distribution set access control. Increase character limit to 512 chars for access control context. Refactor default implementations. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce ContextRunner and define admin execution to check for duplicates before creating/updating entities. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce Software Module, Module Type and Artifact control management. Fix tests. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce access controlling test base. Add first test verifying the read operations for target types. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Finalize target type access controlling test. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce ContextRunnerTest and TargetAccessControllingTest. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce DistributionSetAccessControllingTest and fix missing access control specifications. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Extend test cases. Include only updatable targets into rollout. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Fix action visibility. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Modifiable->Updatable & UPDATE check where needed Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * ContextRunner superseded by ContextAware + ContextRunner remaned to ContextAware (move as a cenral entry/concept). It now extends (and replace) TenantAware + SecurityContextTenantAware becomes ContextAware + Pluggable serialization mechanism (default Java serialization of contexts) for SecurityContextTenantAware (using SecurityContextSerializer) + AccessControl methods are added to ensure no entities fill be retrieved just to call access control - so, if all permitted - no additional db queries will be made + <repo type>AccessControl classes removed and replaced with AccessControl <repo type> generics + AccessControlService removed - every AccessControl is registered and overiden independently + access_control_context in DB increased to 4k (in order to support java security context serialization) + needed adaptaion of implemtation and tests done Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Refactor SoftModules & DistSets Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Refactoring of the Repositories Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Repostiotory level permissions Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Improvements Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Simplification of AccessControl interface * Simplifications & management package Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Implementation improvements + Artifact management & repo reviewed and tuned + Action(Status) management & repo reviewed and tuned + SoftwareModule(Type/Meta) management & repo reviewed and tuned + DistributionSet(Type/Tag/Meta) management(+Invalidation) & repo reviewed and tuned + Target(Tag/Type/Meta) management & repo reviewed and tuned + TargetQueryFilter management & repo reviewed and tuned * Apply suggestions from code review Suggestions accepted. Thanks @herdt-michael Co-authored-by: Michael Herdt <michael.herdt@bosch.com> * Apply suggestions from code review 2 Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> --------- Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> Co-authored-by: Michael Herdt <Michael.Herdt@bosch.com>
This commit is contained in:
@@ -19,6 +19,22 @@ import javax.persistence.PersistenceContext;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutTargetGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
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;
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.eclipse.hawkbit.repository.exception.StopRolloutException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.acm.context;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.security.SecurityContextSerializer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
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;
|
||||
|
||||
@Feature("Component Tests - Context runner")
|
||||
@Story("Test Context Runner")
|
||||
class ContextAwareTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
AutoAssignExecutor autoAssignExecutor;
|
||||
|
||||
@Autowired
|
||||
ContextAware contextAware;
|
||||
|
||||
private static final SecurityContextSerializer SECURITY_CONTEXT_SERIALIZER =
|
||||
SecurityContextSerializer.JAVA_SERIALIZATION;
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void before() {
|
||||
reset(contextAware);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies acm context is persisted when creating Rollout")
|
||||
void verifyAcmContextIsPersistedInCreatedRollout() {
|
||||
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
assertThat(securityContext).isNotNull();
|
||||
|
||||
final Rollout exampleRollout = testdataFactory.createRollout();
|
||||
assertThat(exampleRollout.getAccessControlContext())
|
||||
.hasValueSatisfying(ctx ->
|
||||
assertThat(SECURITY_CONTEXT_SERIALIZER.deserialize(ctx)).isEqualTo(securityContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies acm context is reused when handling a rollout")
|
||||
void verifyContextIsReusedWhenHandlingRollout() {
|
||||
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
assertThat(securityContext).isNotNull();
|
||||
|
||||
// testdataFactory#createRollout will trigger a rollout handling
|
||||
testdataFactory.createRollout();
|
||||
verify(contextAware).runInContext(eq(SECURITY_CONTEXT_SERIALIZER.serialize(securityContext)), any(Runnable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies acm context is persisted when activating auto assignment")
|
||||
void verifyContextIsPersistedInActiveAutoAssignment() {
|
||||
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
assertThat(securityContext).isNotNull();
|
||||
|
||||
final TargetFilterQuery targetFilterQuery = testdataFactory.createTargetFilterWithTargetsAndActiveAutoAssignment();
|
||||
assertThat(targetFilterQuery.getAccessControlContext())
|
||||
.hasValueSatisfying(ctx ->
|
||||
assertThat(SECURITY_CONTEXT_SERIALIZER.deserialize(ctx)).isEqualTo(securityContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies acm context is used when performing auto assign check on all target")
|
||||
void verifyContextIsReusedWhenCheckingForAutoAssignmentAllTargets() {
|
||||
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
assertThat(securityContext).isNotNull();
|
||||
|
||||
testdataFactory.createTargetFilterWithTargetsAndActiveAutoAssignment();
|
||||
autoAssignExecutor.checkAllTargets();
|
||||
verify(contextAware).runInContext(eq(SECURITY_CONTEXT_SERIALIZER.serialize(securityContext)), any(Runnable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies acm context is used when performing auto assign check on single target")
|
||||
void verifyContextIsReusedWhenCheckingForAutoAssignmentSingleTarget() {
|
||||
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
assertThat(securityContext).isNotNull();
|
||||
|
||||
testdataFactory.createTargetFilterWithTargetsAndActiveAutoAssignment();
|
||||
autoAssignExecutor
|
||||
.checkSingleTarget(targetManagement.findAll(Pageable.ofSize(1)).getContent().get(0).getControllerId());
|
||||
verify(contextAware).runInContext(eq(SECURITY_CONTEXT_SERIALIZER.serialize(securityContext)), any(Runnable.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.acm.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
@ContextConfiguration(classes = { AbstractAccessControllerTest.AccessControlTestConfig.class })
|
||||
public abstract class AbstractAccessControllerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
protected TestAccessControlManger testAccessControlManger;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
testAccessControlManger.deleteAllRules();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
testAccessControlManger.deleteAllRules();
|
||||
}
|
||||
|
||||
protected void permitAllOperations(final AccessController.Operation operation) {
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaTarget.class, operation, Specification.where(null), type -> true);
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaTargetType.class, operation, Specification.where(null), type -> true);
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaDistributionSet.class, operation, Specification.where(null), type -> true);
|
||||
}
|
||||
|
||||
public static class AccessControlTestConfig {
|
||||
|
||||
private final ContextAware contextAware = new SecurityContextTenantAware((tenant, username) -> List.of());
|
||||
|
||||
@Bean
|
||||
public ContextAware contextAware() {
|
||||
return contextAware;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestAccessControlManger accessControlTestManger() {
|
||||
return new TestAccessControlManger();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AccessController<JpaTarget> targetAccessController(final TestAccessControlManger testAccessControlManger) {
|
||||
return new AccessController<>() {
|
||||
|
||||
@Override
|
||||
public Optional<Specification<JpaTarget>> getAccessRules(final Operation operation) {
|
||||
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(contextAware.getCurrentUsername())) {
|
||||
// as tenant, no restrictions
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(testAccessControlManger.getAccessRule(JpaTarget.class, operation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertOperationAllowed(final Operation operation, final JpaTarget entity)
|
||||
throws InsufficientPermissionException {
|
||||
testAccessControlManger.assertOperation(JpaTarget.class, operation, List.of(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return AccessController.class.getSimpleName() + '<' + JpaTarget.class.getSimpleName() + '>';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AccessController<JpaTargetType> targetTypeAccessController(
|
||||
final TestAccessControlManger testAccessControlManger) {
|
||||
return new AccessController<>() {
|
||||
|
||||
@Override
|
||||
public Optional<Specification<JpaTargetType>> getAccessRules(final Operation operation) {
|
||||
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(contextAware.getCurrentUsername())) {
|
||||
// as tenant, no restrictions
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(testAccessControlManger.getAccessRule(JpaTargetType.class, operation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertOperationAllowed(final Operation operation, final JpaTargetType entity)
|
||||
throws InsufficientPermissionException {
|
||||
testAccessControlManger.assertOperation(JpaTargetType.class, operation, List.of(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return AccessController.class.getSimpleName() + '<' + JpaTargetType.class.getSimpleName() + '>';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AccessController<JpaDistributionSet> distributionSetAccessController(
|
||||
final TestAccessControlManger testAccessControlManger) {
|
||||
return new AccessController<>() {
|
||||
|
||||
@Override
|
||||
public Optional<Specification<JpaDistributionSet>> getAccessRules(final Operation operation) {
|
||||
if (contextAware.getCurrentTenant() != null && SecurityContextTenantAware.SYSTEM_USER.equals(contextAware.getCurrentUsername())) {
|
||||
// as tenant, no restrictions
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(testAccessControlManger.getAccessRule(JpaDistributionSet.class, operation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertOperationAllowed(final Operation operation, final JpaDistributionSet entity)
|
||||
throws InsufficientPermissionException {
|
||||
testAccessControlManger.assertOperation(JpaDistributionSet.class, operation, List.of(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return AccessController.class.getSimpleName() + '<' + JpaDistributionSet.class.getSimpleName() + '>';
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.acm.controller;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
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.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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 Distribution Set Access Controller")
|
||||
class DistributionSetAccessControllerTest extends AbstractAccessControllerTest {
|
||||
|
||||
@Test
|
||||
@Description("Verifies read access rules for distribution sets")
|
||||
void verifyDistributionSetReadOperations() {
|
||||
permitAllOperations(AccessController.Operation.READ);
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
permitAllOperations(AccessController.Operation.UPDATE);
|
||||
|
||||
final DistributionSet permitted = testdataFactory.createDistributionSet();
|
||||
final DistributionSet hidden = testdataFactory.createDistributionSet();
|
||||
|
||||
final Action permittedAction = testdataFactory.performAssignment(permitted);
|
||||
final Action hiddenAction = testdataFactory.performAssignment(hidden);
|
||||
|
||||
testAccessControlManger.deleteAllRules();
|
||||
|
||||
// define access controlling rule
|
||||
defineAccess(AccessController.Operation.READ, permitted);
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaTarget.class, AccessController.Operation.READ,
|
||||
TargetSpecifications.hasId(permittedAction.getTarget().getId()),
|
||||
target -> target.getId().equals(permittedAction.getTarget().getId()));
|
||||
|
||||
// verify distributionSetManagement#findAll
|
||||
assertThat(distributionSetManagement.findAll(Pageable.unpaged()).get().map(Identifiable::getId).toList())
|
||||
.containsOnly(permitted.getId());
|
||||
|
||||
// verify distributionSetManagement#findByRsql
|
||||
assertThat(distributionSetManagement.findByRsql(Pageable.unpaged(), "name==*").get().map(Identifiable::getId)
|
||||
.toList()).containsOnly(permitted.getId());
|
||||
|
||||
// verify distributionSetManagement#findByCompleted
|
||||
assertThat(distributionSetManagement.findByCompleted(Pageable.unpaged(), true).get().map(Identifiable::getId)
|
||||
.toList()).containsOnly(permitted.getId());
|
||||
|
||||
// verify distributionSetManagement#findByDistributionSetFilter
|
||||
assertThat(distributionSetManagement
|
||||
.findByDistributionSetFilter(Pageable.unpaged(),
|
||||
new DistributionSetFilter.DistributionSetFilterBuilder().setIsDeleted(false).build())
|
||||
.get().map(Identifiable::getId).toList()).containsOnly(permitted.getId());
|
||||
|
||||
// verify distributionSetManagement#get
|
||||
assertThat(distributionSetManagement.get(permitted.getId())).isPresent();
|
||||
assertThat(distributionSetManagement.get(hidden.getId())).isEmpty();
|
||||
|
||||
// verify distributionSetManagement#getWithDetails
|
||||
assertThat(distributionSetManagement.getWithDetails(permitted.getId())).isPresent();
|
||||
assertThat(distributionSetManagement.getWithDetails(hidden.getId())).isEmpty();
|
||||
|
||||
// verify distributionSetManagement#get
|
||||
assertThat(distributionSetManagement.getValid(permitted.getId()).getId()).isEqualTo(permitted.getId());
|
||||
assertThatThrownBy(() -> {
|
||||
assertThat(distributionSetManagement.getValid(hidden.getId()));
|
||||
}).as("Distribution set should not be found.").isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// verify distributionSetManagement#get
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.get(Arrays.asList(permitted.getId(), hidden.getId()));
|
||||
}).as("Fail if request hidden.").isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// verify distributionSetManagement#getByNameAndVersion
|
||||
assertThat(distributionSetManagement.getByNameAndVersion(permitted.getName(), permitted.getVersion()))
|
||||
.isPresent();
|
||||
assertThat(distributionSetManagement.getByNameAndVersion(hidden.getName(), hidden.getVersion())).isEmpty();
|
||||
|
||||
// verify distributionSetManagement#getByAction
|
||||
assertThat(distributionSetManagement.getByAction(permittedAction.getId())).isPresent();
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.getByAction(hiddenAction.getId());
|
||||
}).as("Action is hidden.").isInstanceOf(InsufficientPermissionException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies read access rules for distribution sets")
|
||||
void verifyDistributionSetUpdates() {
|
||||
// permit all operations first to prepare test setup
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
permitAllOperations(AccessController.Operation.UPDATE);
|
||||
|
||||
final DistributionSet permitted = testdataFactory.createDistributionSet();
|
||||
final DistributionSet readOnly = testdataFactory.createDistributionSet();
|
||||
final DistributionSet hidden = testdataFactory.createDistributionSet();
|
||||
|
||||
final SoftwareModule swModule = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
// entities created - reset rules
|
||||
testAccessControlManger.deleteAllRules();
|
||||
// define access controlling rule
|
||||
defineAccess(AccessController.Operation.READ, permitted, readOnly);
|
||||
|
||||
// allow updating the permitted distributionSet
|
||||
defineAccess(AccessController.Operation.READ, permitted);
|
||||
defineAccess(AccessController.Operation.UPDATE, permitted);
|
||||
|
||||
// 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());
|
||||
});
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.assignSoftwareModules(readOnly.getId(),
|
||||
Collections.singletonList(swModule.getId()));
|
||||
}).as("Distribution set not allowed to me modified.").isInstanceOf(EntityNotFoundException.class);
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.assignSoftwareModules(hidden.getId(),
|
||||
Collections.singletonList(swModule.getId()));
|
||||
}).as("Distribution set should not be visible.").isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
final JpaDistributionSetMetadata metadata = new JpaDistributionSetMetadata("test", "test");
|
||||
|
||||
// verify distributionSetManagement#createMetaData
|
||||
distributionSetManagement.createMetaData(permitted.getId(), Collections.singletonList(metadata));
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.createMetaData(readOnly.getId(), Collections.singletonList(metadata));
|
||||
}).as("Distribution set not allowed to me modified.").isInstanceOf(EntityNotFoundException.class);
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.createMetaData(hidden.getId(), Collections.singletonList(metadata));
|
||||
}).as("Distribution set should not be visible.").isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// verify distributionSetManagement#updateMetaData
|
||||
distributionSetManagement.updateMetaData(permitted.getId(), metadata);
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.updateMetaData(readOnly.getId(), metadata);
|
||||
}).as("Distribution set not allowed to me modified.").isInstanceOf(EntityNotFoundException.class);
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.updateMetaData(hidden.getId(), metadata);
|
||||
}).as("Distribution set should not be visible.").isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// verify distributionSetManagement#deleteMetaData
|
||||
distributionSetManagement.deleteMetaData(permitted.getId(), metadata.getKey());
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.deleteMetaData(readOnly.getId(), metadata.getKey());
|
||||
}).as("Distribution set not allowed to me modified.").isInstanceOf(EntityNotFoundException.class);
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.deleteMetaData(hidden.getId(), metadata.getKey());
|
||||
}).as("Distribution set should not be visible.").isInstanceOf(EntityNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyTagFilteringAndManagement() {
|
||||
// permit all operations first to prepare test setup
|
||||
permitAllOperations(AccessController.Operation.READ);
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
permitAllOperations(AccessController.Operation.UPDATE);
|
||||
|
||||
final DistributionSet permitted = testdataFactory.createDistributionSet();
|
||||
final DistributionSet readOnly = testdataFactory.createDistributionSet();
|
||||
final DistributionSet hidden = testdataFactory.createDistributionSet();
|
||||
final DistributionSetTag dsTag = distributionSetTagManagement.create(entityFactory.tag().create().name("dsTag"));
|
||||
|
||||
// perform tag assignment before setting access rules
|
||||
distributionSetManagement.assignTag(Arrays.asList(permitted.getId(), readOnly.getId(), hidden.getId()),
|
||||
dsTag.getId());
|
||||
// entities created - reset rules
|
||||
testAccessControlManger.deleteAllRules();
|
||||
|
||||
// define access controlling rule
|
||||
defineAccess(AccessController.Operation.READ, permitted, readOnly);
|
||||
|
||||
// allow updating the permitted distributionSet
|
||||
defineAccess(AccessController.Operation.UPDATE, permitted);
|
||||
|
||||
assertThat(distributionSetManagement.findByTag(Pageable.unpaged(), dsTag.getId()).get().map(Identifiable::getId)
|
||||
.toList()).containsOnly(permitted.getId(), readOnly.getId());
|
||||
|
||||
assertThat(distributionSetManagement.findByRsqlAndTag(Pageable.unpaged(), "id==*", dsTag.getId()).get()
|
||||
.map(Identifiable::getId).toList()).containsOnly(permitted.getId(), readOnly.getId());
|
||||
|
||||
// verify distributionSetManagement#toggleTagAssignment on permitted target
|
||||
assertThat(distributionSetManagement
|
||||
.toggleTagAssignment(Collections.singletonList(permitted.getId()), dsTag.getName()).getUnassigned())
|
||||
.isEqualTo(1);
|
||||
// verify distributionSetManagement#assignTag on permitted target
|
||||
assertThat(distributionSetManagement.assignTag(Collections.singletonList(permitted.getId()), dsTag.getId()))
|
||||
.hasSize(1);
|
||||
// verify distributionSetManagement#unAssignTag on permitted target
|
||||
assertThat(distributionSetManagement.unAssignTag(permitted.getId(), dsTag.getId()).getId())
|
||||
.isEqualTo(permitted.getId());
|
||||
|
||||
// assignment is denied for readOnlyTarget (read, but no update permissions)
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.toggleTagAssignment(Collections.singletonList(readOnly.getId()), dsTag.getName())
|
||||
.getUnassigned();
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(InsufficientPermissionException.class);
|
||||
|
||||
// assignment is denied for readOnlyTarget (read, but no update permissions)
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.assignTag(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)
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.unAssignTag(readOnly.getId(), dsTag.getId());
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(InsufficientPermissionException.class);
|
||||
|
||||
// assignment is denied for hiddenTarget since it's hidden
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.toggleTagAssignment(Collections.singletonList(hidden.getId()), dsTag.getName())
|
||||
.getUnassigned();
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// assignment is denied for hiddenTarget since it's hidden
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.assignTag(Collections.singletonList(hidden.getId()), dsTag.getId());
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// assignment is denied for hiddenTarget since it's hidden
|
||||
assertThatThrownBy(() -> {
|
||||
distributionSetManagement.unAssignTag(hidden.getId(), dsTag.getId());
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(EntityNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyAutoAssignmentUsage() {
|
||||
// permit all operations first to prepare test setup
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
permitAllOperations(AccessController.Operation.UPDATE);
|
||||
|
||||
final DistributionSet permitted = testdataFactory.createDistributionSet();
|
||||
final DistributionSet readOnly = testdataFactory.createDistributionSet();
|
||||
final DistributionSet hidden = testdataFactory.createDistributionSet();
|
||||
|
||||
// entities created - reset rules
|
||||
testAccessControlManger.deleteAllRules();
|
||||
// define read access
|
||||
defineAccess(AccessController.Operation.READ, permitted, readOnly);
|
||||
// permit update operation
|
||||
defineAccess(AccessController.Operation.UPDATE, permitted);
|
||||
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("test").query("id==*"));
|
||||
|
||||
assertThat(targetFilterQueryManagement
|
||||
.updateAutoAssignDS(new AutoAssignDistributionSetUpdate(targetFilterQuery.getId()).ds(permitted.getId())
|
||||
.actionType(Action.ActionType.FORCED).confirmationRequired(false))
|
||||
.getAutoAssignDistributionSet().getId()).isEqualTo(permitted.getId());
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDS(new AutoAssignDistributionSetUpdate(targetFilterQuery.getId())
|
||||
.ds(readOnly.getId()).actionType(Action.ActionType.FORCED).confirmationRequired(false))
|
||||
.getAutoAssignDistributionSet().getId();
|
||||
assertThatThrownBy(() -> {
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDS(new AutoAssignDistributionSetUpdate(targetFilterQuery.getId())
|
||||
.ds(hidden.getId()).actionType(Action.ActionType.FORCED).confirmationRequired(false))
|
||||
.getAutoAssignDistributionSet().getId();
|
||||
}).isInstanceOf(EntityNotFoundException.class);
|
||||
}
|
||||
|
||||
|
||||
private void defineAccess(final AccessController.Operation operation, final DistributionSet... distributionSets) {
|
||||
defineAccess(operation, List.of(distributionSets));
|
||||
}
|
||||
|
||||
private void defineAccess(final AccessController.Operation operation, final List<DistributionSet> targets) {
|
||||
final List<Long> ids = targets.stream().map(DistributionSet::getId).toList();
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaDistributionSet.class, operation,
|
||||
DistributionSetSpecification.byIds(ids),
|
||||
distributionSet -> ids.contains(distributionSet.getId()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.acm.controller;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.autoassign.AutoAssignChecker;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
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 {
|
||||
|
||||
@Autowired
|
||||
AutoAssignChecker autoAssignChecker;
|
||||
|
||||
@Test
|
||||
@Description("Verifies read access rules for targets")
|
||||
void verifyTargetReadOperations() {
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
|
||||
final Target permittedTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device01").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
final Target hiddenTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device02").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
// define access controlling rule
|
||||
defineAccess(AccessController.Operation.READ, permittedTarget);
|
||||
|
||||
// verify targetManagement#findAll
|
||||
assertThat(targetManagement.findAll(Pageable.unpaged()).get().map(Identifiable::getId).toList())
|
||||
.containsOnly(permittedTarget.getId());
|
||||
|
||||
// verify targetManagement#findByRsql
|
||||
assertThat(targetManagement.findByRsql(Pageable.unpaged(), "id==*").get().map(Identifiable::getId).toList())
|
||||
.containsOnly(permittedTarget.getId());
|
||||
|
||||
// verify targetManagement#findByUpdateStatus
|
||||
assertThat(targetManagement.findByUpdateStatus(Pageable.unpaged(), TargetUpdateStatus.REGISTERED).get()
|
||||
.map(Identifiable::getId).toList()).containsOnly(permittedTarget.getId());
|
||||
|
||||
// verify targetManagement#getByControllerID
|
||||
assertThat(targetManagement.getByControllerID(permittedTarget.getControllerId())).isPresent();
|
||||
assertThat(targetManagement.getByControllerID(hiddenTarget.getControllerId())).isEmpty();
|
||||
|
||||
// verify targetManagement#getByControllerID
|
||||
assertThat(targetManagement
|
||||
.getByControllerID(Arrays.asList(permittedTarget.getControllerId(), hiddenTarget.getControllerId()))
|
||||
.stream().map(Identifiable::getId).toList()).containsOnly(permittedTarget.getId());
|
||||
|
||||
// verify targetManagement#get
|
||||
assertThat(targetManagement.get(permittedTarget.getId())).isPresent();
|
||||
assertThat(targetManagement.get(hiddenTarget.getId())).isEmpty();
|
||||
|
||||
// verify targetManagement#get
|
||||
assertThat(targetManagement.get(Arrays.asList(permittedTarget.getId(), hiddenTarget.getId())).stream()
|
||||
.map(Identifiable::getId).toList()).containsOnly(permittedTarget.getId());
|
||||
|
||||
// verify targetManagement#getControllerAttributes
|
||||
assertThat(targetManagement.getControllerAttributes(permittedTarget.getControllerId())).isEmpty();
|
||||
assertThatThrownBy(() -> {
|
||||
assertThat(targetManagement.getControllerAttributes(hiddenTarget.getControllerId())).isEmpty();
|
||||
}).as("Target should not be found.").isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("test").query("id==*"));
|
||||
|
||||
// verify targetManagement#findByTargetFilterQuery
|
||||
assertThat(targetManagement.findByTargetFilterQuery(Pageable.unpaged(), targetFilterQuery.getId()).get()
|
||||
.map(Identifiable::getId).toList()).containsOnly(permittedTarget.getId());
|
||||
|
||||
// verify targetManagement#findByTargetFilterQuery (used by UI)
|
||||
assertThat(targetManagement.findByFilters(Pageable.unpaged(), new FilterParams(null, null, null, null)).get()
|
||||
.map(Identifiable::getId).toList()).containsOnly(permittedTarget.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyTagFilteringAndManagement() {
|
||||
// permit all operations first to prepare test setup
|
||||
permitAllOperations(AccessController.Operation.READ);
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
permitAllOperations(AccessController.Operation.UPDATE);
|
||||
|
||||
final Target permittedTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device01").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
final Target readOnlyTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device02").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
final Target hiddenTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device03").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
final TargetTag myTag = targetTagManagement.create(entityFactory.tag().create().name("myTag"));
|
||||
|
||||
// perform tag assignment before setting access rules
|
||||
targetManagement.assignTag(Arrays.asList(permittedTarget.getControllerId(), readOnlyTarget.getControllerId(),
|
||||
hiddenTarget.getControllerId()), myTag.getId());
|
||||
|
||||
// define access controlling rule
|
||||
testAccessControlManger.deleteAllRules();
|
||||
defineAccess(AccessController.Operation.READ, permittedTarget, readOnlyTarget);
|
||||
// allow update operation
|
||||
// allow update operation
|
||||
defineAccess(AccessController.Operation.UPDATE, permittedTarget);
|
||||
|
||||
// verify targetManagement#findByTag
|
||||
assertThat(
|
||||
targetManagement.findByTag(Pageable.unpaged(), myTag.getId()).get().map(Identifiable::getId).toList())
|
||||
.containsOnly(permittedTarget.getId(), readOnlyTarget.getId());
|
||||
|
||||
// verify targetManagement#findByRsqlAndTag
|
||||
assertThat(targetManagement.findByRsqlAndTag(Pageable.unpaged(), "id==*", myTag.getId()).get()
|
||||
.map(Identifiable::getId).toList()).containsOnly(permittedTarget.getId(), readOnlyTarget.getId());
|
||||
|
||||
// verify targetManagement#toggleTagAssignment on permitted target
|
||||
assertThat(targetManagement
|
||||
.toggleTagAssignment(Collections.singletonList(permittedTarget.getControllerId()), myTag.getName())
|
||||
.getUnassigned()).isEqualTo(1);
|
||||
// verify targetManagement#assignTag on permitted target
|
||||
assertThat(
|
||||
targetManagement.assignTag(Collections.singletonList(permittedTarget.getControllerId()), myTag.getId()))
|
||||
.hasSize(1);
|
||||
// verify targetManagement#unAssignTag on permitted target
|
||||
assertThat(targetManagement.unassignTag(permittedTarget.getControllerId(), myTag.getId()).getControllerId())
|
||||
.isEqualTo(permittedTarget.getControllerId());
|
||||
|
||||
// assignment is denied for readOnlyTarget (read, but no update permissions)
|
||||
// No exception has been thrown - because no real change is done
|
||||
// assertThatThrownBy(() -> {
|
||||
// targetManagement
|
||||
// .toggleTagAssignment(List.of(readOnlyTarget.getControllerId()), myTag.getName())
|
||||
// .getUnassigned();
|
||||
// }).as("Missing update permissions for target to toggle tag assignment.")
|
||||
// .isInstanceOf(InsufficientPermissionException.class);
|
||||
|
||||
// assignment is denied for readOnlyTarget (read, but no update permissions)
|
||||
assertThatThrownBy(() -> {
|
||||
targetManagement.assignTag(Collections.singletonList(readOnlyTarget.getControllerId()), myTag.getId());
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOfAny(InsufficientPermissionException.class, EntityNotFoundException.class);
|
||||
|
||||
// assignment is denied for readOnlyTarget (read, but no update permissions)
|
||||
assertThatThrownBy(() -> {
|
||||
targetManagement.unassignTag(readOnlyTarget.getControllerId(), myTag.getId());
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(InsufficientPermissionException.class);
|
||||
|
||||
// assignment is denied for hiddenTarget since it's hidden
|
||||
assertThatThrownBy(() -> {
|
||||
targetManagement
|
||||
.toggleTagAssignment(Collections.singletonList(hiddenTarget.getControllerId()), myTag.getName())
|
||||
.getUnassigned();
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// assignment is denied for hiddenTarget since it's hidden
|
||||
assertThatThrownBy(() -> {
|
||||
targetManagement.assignTag(Collections.singletonList(hiddenTarget.getControllerId()), myTag.getId());
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// assignment is denied for hiddenTarget since it's hidden
|
||||
assertThatThrownBy(() -> {
|
||||
targetManagement.unassignTag(hiddenTarget.getControllerId(), myTag.getId());
|
||||
}).as("Missing update permissions for target to toggle tag assignment.")
|
||||
.isInstanceOf(EntityNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies rules for target assignment")
|
||||
void verifyTargetAssignment() {
|
||||
permitAllOperations(AccessController.Operation.READ);
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
|
||||
final Target permittedTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device01").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
final Target hiddenTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device02").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("myDs");
|
||||
|
||||
// define access controlling rule
|
||||
defineAccess(AccessController.Operation.READ, permittedTarget);
|
||||
|
||||
// verify targetManagement#findByUpdateStatus before assignment
|
||||
assertThat(targetManagement.findByUpdateStatus(Pageable.unpaged(), TargetUpdateStatus.REGISTERED).get()
|
||||
.map(Identifiable::getId).toList()).containsOnly(permittedTarget.getId());
|
||||
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaTarget.class, AccessController.Operation.UPDATE,
|
||||
TargetSpecifications.hasId(permittedTarget.getId()),
|
||||
target -> target.getId().equals(permittedTarget.getId()));
|
||||
|
||||
assertThat(assignDistributionSet(ds.getId(), permittedTarget.getControllerId()).getAssigned()).isEqualTo(1);
|
||||
// assigning of non allowed target behaves as not found
|
||||
assertThatThrownBy(
|
||||
() -> assignDistributionSet(ds.getId(), hiddenTarget.getControllerId())
|
||||
).isInstanceOf(AssertionError.class);
|
||||
|
||||
// verify targetManagement#findByUpdateStatus(REGISTERED) after assignment
|
||||
assertThat(targetManagement.findByUpdateStatus(Pageable.unpaged(), TargetUpdateStatus.REGISTERED)
|
||||
.getTotalElements()).isZero();
|
||||
|
||||
// verify targetManagement#findByUpdateStatus(PENDING) after assignment
|
||||
assertThat(targetManagement.findByUpdateStatus(Pageable.unpaged(), TargetUpdateStatus.PENDING).get()
|
||||
.map(Identifiable::getId).toList()).containsOnly(permittedTarget.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies rules for target assignment")
|
||||
void verifyTargetAssignmentOnNonUpdatableTarget() {
|
||||
permitAllOperations(AccessController.Operation.READ);
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
|
||||
final Target manageableTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device01").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
final Target readOnlyTarget = targetManagement
|
||||
.create(entityFactory.target().create().controllerId("device02").status(TargetUpdateStatus.REGISTERED));
|
||||
|
||||
final DistributionSet firstDs = testdataFactory.createDistributionSet("myDs");
|
||||
|
||||
// define access controlling rule
|
||||
defineAccess(AccessController.Operation.READ, manageableTarget, readOnlyTarget);
|
||||
|
||||
defineAccess(AccessController.Operation.UPDATE, manageableTarget);
|
||||
|
||||
// assignment is permitted for manageableTarget
|
||||
assertThat(assignDistributionSet(firstDs.getId(), manageableTarget.getControllerId()).getAssigned())
|
||||
.isEqualTo(1);
|
||||
|
||||
// assignment is denied for readOnlyTarget (read, but no update permissions)
|
||||
assertThatThrownBy(
|
||||
() -> assignDistributionSet(firstDs.getId(), readOnlyTarget.getControllerId())
|
||||
).isInstanceOf(AssertionError.class);
|
||||
|
||||
final DistributionSet secondDs = testdataFactory.createDistributionSet("anotherDs");
|
||||
|
||||
// bunch assignment skips denied denied since at least one target without update
|
||||
// permissions is present
|
||||
assertThat(assignDistributionSet(secondDs.getId(),
|
||||
Arrays.asList(readOnlyTarget.getControllerId(), manageableTarget.getControllerId()),
|
||||
Action.ActionType.FORCED).getAssigned()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies only manageable targets are part of the rollout")
|
||||
void verifyRolloutTargetScope() {
|
||||
permitAllOperations(AccessController.Operation.READ);
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
|
||||
final List<Target> updateTargets = testdataFactory.createTargets("update1", "update2", "update3");
|
||||
final List<Target> readTargets = testdataFactory.createTargets("read1", "read2", "read3", "read4");
|
||||
final List<Target> hiddenTargets = testdataFactory.createTargets("hidden1", "hidden2", "hidden3", "hidden4",
|
||||
"hidden5");
|
||||
|
||||
defineAccess(AccessController.Operation.UPDATE, updateTargets);
|
||||
defineAccess(AccessController.Operation.READ, merge(readTargets, updateTargets));
|
||||
|
||||
final Rollout rollout = testdataFactory.createRolloutByVariables("testRollout", "description",
|
||||
updateTargets.size(), "id==*", testdataFactory.createDistributionSet(), "50", "5");
|
||||
|
||||
assertThat(rollout.getTotalTargets()).isEqualTo(updateTargets.size());
|
||||
|
||||
final List<RolloutGroup> content = rolloutGroupManagement.findByRollout(Pageable.unpaged(), rollout.getId())
|
||||
.getContent();
|
||||
assertThat(content).hasSize(updateTargets.size());
|
||||
|
||||
final List<Target> rolloutTargets = content.stream().flatMap(
|
||||
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())))
|
||||
.noneMatch(target -> readTargets.stream()
|
||||
.anyMatch(readTarget -> readTarget.getId().equals(target.getId())))
|
||||
.noneMatch(target -> hiddenTargets.stream()
|
||||
.anyMatch(readTarget -> readTarget.getId().equals(target.getId())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies only manageable targets are part of an auto assignment.")
|
||||
void verifyAutoAssignmentTargetScope() {
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
|
||||
final List<Target> updateTargets = testdataFactory.createTargets("update1", "update2", "update3");
|
||||
final List<Target> readTargets = testdataFactory.createTargets("read1", "read2", "read3", "read4");
|
||||
final List<Target> hiddenTargets = testdataFactory.createTargets("hidden1", "hidden2", "hidden3", "hidden4",
|
||||
"hidden5");
|
||||
|
||||
defineAccess(AccessController.Operation.UPDATE, updateTargets);
|
||||
defineAccess(AccessController.Operation.READ, merge(updateTargets, readTargets));;
|
||||
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("testName").query("id==*"));
|
||||
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaDistributionSet.class, AccessController.Operation.READ,
|
||||
DistributionSetSpecification.byId(distributionSet.getId()),
|
||||
ds -> ds.getId().equals(distributionSet.getId()));
|
||||
|
||||
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()));
|
||||
|
||||
autoAssignChecker.checkAllTargets();
|
||||
|
||||
assertThat(targetManagement.findByAssignedDistributionSet(Pageable.unpaged(), distributionSet.getId())
|
||||
.getContent())
|
||||
.hasSize(updateTargets.size())
|
||||
.allMatch(assignedTarget -> updateTargets.stream()
|
||||
.anyMatch(updateTarget -> updateTarget.getId().equals(assignedTarget.getId())))
|
||||
.noneMatch(assignedTarget -> readTargets.stream()
|
||||
.anyMatch(updateTarget -> updateTarget.getId().equals(assignedTarget.getId())))
|
||||
.noneMatch(assignedTarget -> hiddenTargets.stream()
|
||||
.anyMatch(updateTarget -> updateTarget.getId().equals(assignedTarget.getId())));
|
||||
}
|
||||
|
||||
private void defineAccess(final AccessController.Operation operation, final Target... target) {
|
||||
defineAccess(operation, List.of(target));
|
||||
}
|
||||
|
||||
private void defineAccess(final AccessController.Operation operation, final List<Target> targets) {
|
||||
final List<Long> ids = targets.stream().map(Target::getId).toList();
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaTarget.class, operation,
|
||||
TargetSpecifications.hasIdIn(ids),
|
||||
target -> ids.contains(target.getId()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.acm.controller;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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 Type Access Controller")
|
||||
class TargetTypeAccessControllerTest extends AbstractAccessControllerTest {
|
||||
|
||||
@Test
|
||||
@Description("Verifies read access rules for target types")
|
||||
void verifyTargetTypeReadOperations() {
|
||||
permitAllOperations(AccessController.Operation.READ);
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
|
||||
final TargetType permittedTargetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("type1"));
|
||||
|
||||
final TargetType hiddenTargetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("type2"));
|
||||
|
||||
// create target and assign with hidden target type
|
||||
final Target targetWithHiddenTargetType = targetManagement.create(entityFactory.target().create()
|
||||
.controllerId("targetWithUnseeableTargetType").targetType(hiddenTargetType.getId()));
|
||||
|
||||
// create target and assign with permitted target type
|
||||
final Target targetWithPermittedTargetType = targetManagement.create(entityFactory.target().create()
|
||||
.controllerId("targetWithPermittedTargetType").targetType(permittedTargetType.getId()));
|
||||
|
||||
// define access controlling rule
|
||||
defineAccess(AccessController.Operation.READ, permittedTargetType);
|
||||
|
||||
// verify targetTypeManagement#findAll
|
||||
assertThat(targetTypeManagement.findAll(Pageable.unpaged()).get().map(Identifiable::getId).toList())
|
||||
.containsOnly(permittedTargetType.getId());
|
||||
|
||||
// verify targetTypeManagement#findByRsql
|
||||
assertThat(targetTypeManagement.findByRsql(Pageable.unpaged(), "id==*").get().map(Identifiable::getId).toList())
|
||||
.containsOnly(permittedTargetType.getId());
|
||||
|
||||
// verify targetTypeManagement#findByTargetControllerId
|
||||
assertThat(targetTypeManagement.findByTargetControllerId(targetWithPermittedTargetType.getControllerId()))
|
||||
.hasValueSatisfying(foundType -> assertThat(foundType.getId()).isEqualTo(permittedTargetType.getId()));
|
||||
assertThat(targetTypeManagement.findByTargetControllerId(targetWithHiddenTargetType.getControllerId()))
|
||||
.isEmpty();
|
||||
|
||||
// verify targetTypeManagement#findByTargetControllerIds
|
||||
assertThat(
|
||||
targetTypeManagement
|
||||
.findByTargetControllerIds(Arrays.asList(targetWithPermittedTargetType.getControllerId(),
|
||||
targetWithHiddenTargetType.getControllerId()))
|
||||
.stream().map(Identifiable::getId).toList())
|
||||
.hasSize(1).containsOnly(permittedTargetType.getId());
|
||||
|
||||
// verify targetTypeManagement#findByTargetId
|
||||
assertThat(targetTypeManagement.findByTargetId(targetWithPermittedTargetType.getId()))
|
||||
.hasValueSatisfying(foundType -> assertThat(foundType.getId()).isEqualTo(permittedTargetType.getId()));
|
||||
assertThat(targetTypeManagement.findByTargetId(targetWithHiddenTargetType.getId())).isEmpty();
|
||||
|
||||
// verify targetTypeManagement#findByTargetIds
|
||||
assertThat(targetTypeManagement
|
||||
.findByTargetIds(
|
||||
Arrays.asList(targetWithPermittedTargetType.getId(), targetWithHiddenTargetType.getId()))
|
||||
.stream().map(Identifiable::getId).toList()).hasSize(1).containsOnly(permittedTargetType.getId());
|
||||
|
||||
// verify targetTypeManagement#findByName
|
||||
assertThat(targetTypeManagement.findByName(Pageable.unpaged(), permittedTargetType.getName()).getContent())
|
||||
.hasSize(1).satisfies(results -> {
|
||||
assertThat(results.get(0).getId()).isEqualTo(permittedTargetType.getId());
|
||||
});
|
||||
assertThat(targetTypeManagement.findByName(Pageable.unpaged(), hiddenTargetType.getName())).isEmpty();
|
||||
|
||||
// verify targetTypeManagement#count
|
||||
assertThat(targetTypeManagement.count()).isEqualTo(1);
|
||||
|
||||
// verify targetTypeManagement#countByName
|
||||
// assertThat(targetTypeManagement.countByName(permittedTargetType.getName())).isEqualTo(1);
|
||||
// assertThat(targetTypeManagement.countByName(hiddenTargetType.getName())).isZero();
|
||||
|
||||
// verify targetTypeManagement#countByName
|
||||
// assertThat(targetTypeManagement.countByName(permittedTargetType.getName())).isEqualTo(1);
|
||||
// assertThat(targetTypeManagement.countByName(hiddenTargetType.getName())).isZero();
|
||||
|
||||
// verify targetTypeManagement#get by id
|
||||
assertThat(targetTypeManagement.get(permittedTargetType.getId())).isPresent();
|
||||
assertThat(targetTypeManagement.get(hiddenTargetType.getId())).isEmpty();
|
||||
|
||||
// verify targetTypeManagement#getByName
|
||||
assertThat(targetTypeManagement.getByName(permittedTargetType.getName())).isPresent();
|
||||
assertThat(targetTypeManagement.getByName(hiddenTargetType.getName())).isEmpty();
|
||||
|
||||
// verify targetTypeManagement#get by ids
|
||||
assertThat(targetTypeManagement.get(Arrays.asList(permittedTargetType.getId(), hiddenTargetType.getId()))
|
||||
.stream().map(Identifiable::getId).toList()).containsOnly(permittedTargetType.getId());
|
||||
|
||||
// verify targetTypeManagement#update is not possible. Assert exception thrown.
|
||||
assertThatThrownBy(() -> targetTypeManagement.update(entityFactory.targetType().update(hiddenTargetType.getId())
|
||||
.name(hiddenTargetType.getName() + "/new").description("newDesc")))
|
||||
.as("Target type update shouldn't be allowed since the target type is not visible.")
|
||||
.isInstanceOf(EntityNotFoundException.class);
|
||||
|
||||
// verify targetTypeManagement#delete is not possible. Assert exception thrown.
|
||||
assertThatThrownBy(() -> targetTypeManagement.delete(hiddenTargetType.getId()))
|
||||
.as("Target type delete shouldn't be allowed since the target type is not visible.")
|
||||
.isInstanceOf(EntityNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies delete access rules for target types")
|
||||
void verifyTargetTypeDeleteOperations() {
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
final TargetType manageableTargetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("type1"));
|
||||
|
||||
final TargetType readOnlyTargetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("type2"));
|
||||
|
||||
// define access controlling rule to allow reading both types
|
||||
defineAccess(AccessController.Operation.READ, manageableTargetType, readOnlyTargetType);
|
||||
|
||||
// permit operation to delete permittedTargetType
|
||||
defineAccess(AccessController.Operation.DELETE, manageableTargetType);
|
||||
|
||||
// delete the manageableTargetType
|
||||
targetTypeManagement.delete(manageableTargetType.getId());
|
||||
|
||||
// verify targetTypeManagement#delete for readOnlyTargetType is not possible
|
||||
assertThatThrownBy(() -> {
|
||||
targetTypeManagement.delete(readOnlyTargetType.getId());
|
||||
}).isInstanceOfAny(InsufficientPermissionException.class, EntityNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies update operation for target types")
|
||||
void verifyTargetTypeUpdateOperations() {
|
||||
permitAllOperations(AccessController.Operation.CREATE);
|
||||
final TargetType manageableTargetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("type1"));
|
||||
|
||||
final TargetType readOnlyTargetType = targetTypeManagement
|
||||
.create(entityFactory.targetType().create().name("type2"));
|
||||
|
||||
// define access controlling rule to allow reading both types
|
||||
defineAccess(AccessController.Operation.READ, manageableTargetType, readOnlyTargetType);
|
||||
|
||||
// permit updating the manageableTargetType
|
||||
defineAccess(AccessController.Operation.UPDATE, manageableTargetType);
|
||||
|
||||
// update the manageableTargetType
|
||||
targetTypeManagement.update(entityFactory.targetType().update(manageableTargetType.getId())
|
||||
.name(manageableTargetType.getName() + "/new").description("newDesc"));
|
||||
|
||||
// verify targetTypeManagement#update for readOnlyTargetType is not possible
|
||||
assertThatThrownBy(() -> {
|
||||
targetTypeManagement.update(entityFactory.targetType().update(readOnlyTargetType.getId())
|
||||
.name(readOnlyTargetType.getName() + "/new").description("newDesc"));
|
||||
}).isInstanceOf(InsufficientPermissionException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies create operation blocked by controller")
|
||||
void verifyTargetTypeCreationBlockedByAccessController() {
|
||||
defineAccess(AccessController.Operation.CREATE); // allows for none
|
||||
// verify targetTypeManagement#create for any type
|
||||
assertThatThrownBy(() -> targetTypeManagement.create(entityFactory.targetType().create().name("type1")))
|
||||
.as("Target type create shouldn't be allowed since the target type is not visible.")
|
||||
.isInstanceOf(InsufficientPermissionException.class);
|
||||
}
|
||||
|
||||
private void defineAccess(final AccessController.Operation operation, final TargetType... targetType) {
|
||||
defineAccess(operation, List.of(targetType));
|
||||
}
|
||||
|
||||
private void defineAccess(final AccessController.Operation operation, final List<TargetType> targetTypes) {
|
||||
final List<Long> ids = targetTypes.stream().map(TargetType::getId).toList();
|
||||
testAccessControlManger.defineAccessRule(
|
||||
JpaTargetType.class, operation,
|
||||
TargetTypeSpecification.hasIdIn(ids),
|
||||
targetType -> ids.contains(targetType.getId()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.acm.controller;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
|
||||
public class TestAccessControlManger {
|
||||
|
||||
private final Map<AccessRuleId<?>, AccessRule<?>> accessRules = new HashMap<>();
|
||||
|
||||
public void deleteAllRules() {
|
||||
accessRules.clear();
|
||||
}
|
||||
|
||||
public <T> void defineAccessRule(
|
||||
final Class<T> ruleClass, final AccessController.Operation operation,
|
||||
final Specification<T> specification, final Predicate<T> check) {
|
||||
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);
|
||||
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);
|
||||
if (accessRule == null) {
|
||||
throw new InsufficientPermissionException("No access define - reject all");
|
||||
} else {
|
||||
for (final T entity : entities) {
|
||||
if (!accessRule.checker.test(entity)) {
|
||||
throw new InsufficientPermissionException(
|
||||
"Access to " + ruleClass.getName() + "/" + entity + " not allowed by checker!");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private record AccessRuleId<T>(Class<T> ruleClass, AccessController.Operation operation) {}
|
||||
private record AccessRule<T> (Specification<T> specification, Predicate<T> checker) {}
|
||||
}
|
||||
@@ -20,9 +20,10 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -58,7 +59,7 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
|
||||
private AutoAssignChecker autoAssignChecker;
|
||||
|
||||
@Autowired
|
||||
private ActionRepository actionRepository;
|
||||
private DeploymentManagement deploymentManagement;
|
||||
|
||||
@Test
|
||||
@Description("Verifies that a running action is auto canceled by a AutoAssignment which assigns another distribution-set.")
|
||||
@@ -141,7 +142,7 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
|
||||
verifyThatTargetsHaveDistributionSetAssignment(setB, targets.subList(10, 20), targetsCount);
|
||||
|
||||
// Count the number of targets that will be assigned with setA
|
||||
assertThat(targetManagement.countByRsqlAndNonDSAndCompatible(setA.getId(), targetFilterQuery.getQuery()))
|
||||
assertThat(targetManagement.countByRsqlAndNonDSAndCompatibleAndUpdatable(setA.getId(), targetFilterQuery.getQuery()))
|
||||
.isEqualTo(15);
|
||||
|
||||
// Run the check
|
||||
@@ -322,7 +323,7 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(targetsWithAssignedDS).isNotEmpty();
|
||||
assertThat(targetsWithAssignedDS).allMatch(target -> targetIds.contains(target.getControllerId()));
|
||||
|
||||
final List<Action> actionsByDs = deploymentManagement.findActionsByDistributionSet(PAGE, set.getId())
|
||||
final List<Action> actionsByDs = findActionsByDistributionSet(PAGE, set.getId())
|
||||
.getContent();
|
||||
|
||||
assertThat(actionsByDs).hasSize(targets.size());
|
||||
@@ -349,7 +350,7 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
|
||||
final DistributionSet distributionSet, final List<Target> targets) {
|
||||
final Set<String> targetIds = targets.stream().map(Target::getControllerId).collect(Collectors.toSet());
|
||||
|
||||
actionRepository.findByDistributionSetId(Pageable.unpaged(), distributionSet.getId()).stream()
|
||||
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")
|
||||
@@ -480,7 +481,7 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
|
||||
final List<Long> compatibleTargets = Stream
|
||||
.of(compatibleTargetsSingleType, compatibleTargetsMultiType, compatibleTargetsWithoutType)
|
||||
.flatMap(Collection::stream).map(Target::getId).collect(Collectors.toList());
|
||||
final long compatibleCount = targetManagement.countByRsqlAndNonDSAndCompatible(testDs.getId(),
|
||||
final long compatibleCount = targetManagement.countByRsqlAndNonDSAndCompatibleAndUpdatable(testDs.getId(),
|
||||
testFilter.getQuery());
|
||||
assertThat(compatibleCount).isEqualTo(compatibleTargets.size());
|
||||
|
||||
@@ -491,4 +492,10 @@ class AutoAssignCheckerIntTest extends AbstractJpaIntegrationTest {
|
||||
final List<Long> actionTargets = actions.stream().map(a -> a.getTarget().getId()).collect(Collectors.toList());
|
||||
assertThat(actionTargets).containsExactlyInAnyOrderElementsOf(compatibleTargets);
|
||||
}
|
||||
|
||||
private Slice<Action> findActionsByDistributionSet(final Pageable pageable, final long distributionSetId) {
|
||||
return actionRepository
|
||||
.findAll(ActionSpecifications.byDistributionSetId(distributionSetId), pageable)
|
||||
.map(Action.class::cast);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,14 @@ package org.eclipse.hawkbit.repository.jpa.autoassign;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
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 static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
@@ -55,14 +53,14 @@ class AutoAssignCheckerTest {
|
||||
@Mock
|
||||
private PlatformTransactionManager transactionManager;
|
||||
@Mock
|
||||
private TenantAware tenantAware;
|
||||
private ContextAware contextAware;
|
||||
|
||||
private AutoAssignChecker sut;
|
||||
|
||||
@BeforeEach
|
||||
void before() {
|
||||
sut = new AutoAssignChecker(targetFilterQueryManagement, targetManagement, deploymentManagement,
|
||||
transactionManager, tenantAware);
|
||||
transactionManager, contextAware);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -78,8 +76,8 @@ class AutoAssignCheckerTest {
|
||||
|
||||
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, matching.getQuery()))
|
||||
.thenReturn(true);
|
||||
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds,
|
||||
notMatching.getQuery())).thenReturn(false);
|
||||
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, notMatching.getQuery()))
|
||||
.thenReturn(false);
|
||||
|
||||
sut.checkSingleTarget(target);
|
||||
|
||||
@@ -107,7 +105,9 @@ class AutoAssignCheckerTest {
|
||||
}
|
||||
|
||||
private void mockRunningAsNonSystem() {
|
||||
when(tenantAware.getCurrentUsername()).thenReturn(getRandomString());
|
||||
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() {
|
||||
|
||||
@@ -118,7 +118,7 @@ public class AutoActionCleanupTest extends AbstractJpaIntegrationTest {
|
||||
autoActionCleanup.run();
|
||||
|
||||
assertThat(actionRepository.count()).isEqualTo(1);
|
||||
assertThat(actionRepository.getActionById(action3)).isPresent();
|
||||
assertThat(actionRepository.findWithDetailsById(action3)).isPresent();
|
||||
|
||||
}
|
||||
|
||||
@@ -150,8 +150,8 @@ public class AutoActionCleanupTest extends AbstractJpaIntegrationTest {
|
||||
autoActionCleanup.run();
|
||||
|
||||
assertThat(actionRepository.count()).isEqualTo(2);
|
||||
assertThat(actionRepository.getActionById(action2)).isPresent();
|
||||
assertThat(actionRepository.getActionById(action3)).isPresent();
|
||||
assertThat(actionRepository.findWithDetailsById(action2)).isPresent();
|
||||
assertThat(actionRepository.findWithDetailsById(action3)).isPresent();
|
||||
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ public class AutoActionCleanupTest extends AbstractJpaIntegrationTest {
|
||||
autoActionCleanup.run();
|
||||
|
||||
assertThat(actionRepository.count()).isEqualTo(1);
|
||||
assertThat(actionRepository.getActionById(action3)).isPresent();
|
||||
assertThat(actionRepository.findWithDetailsById(action3)).isPresent();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -40,6 +40,8 @@ import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA256HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.RandomGeneratedInputStream;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
@@ -129,7 +131,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
try (final InputStream inputStream1 = new ByteArrayInputStream(randomBytes);
|
||||
final InputStream inputStream2 = new ByteArrayInputStream(randomBytes);
|
||||
final InputStream inputStream3 = new ByteArrayInputStream(randomBytes);
|
||||
final InputStream inputStream4 = new ByteArrayInputStream(randomBytes);) {
|
||||
final InputStream inputStream4 = new ByteArrayInputStream(randomBytes)) {
|
||||
|
||||
final Artifact artifact1 = createArtifactForSoftwareModule("file1", sm.getId(), artifactSize, inputStream1);
|
||||
createArtifactForSoftwareModule("file11", sm.getId(), artifactSize, inputStream2);
|
||||
@@ -178,7 +180,6 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
@Description("Verifies that the quota specifying the maximum number of artifacts per software module is enforced.")
|
||||
public void createArtifactsUntilQuotaIsExceeded() throws IOException {
|
||||
|
||||
// create a software module
|
||||
final long smId = softwareModuleRepository.save(new JpaSoftwareModule(osType, "sm1", "1.0")).getId();
|
||||
|
||||
@@ -189,7 +190,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
for (int i = 0; i < maxArtifacts; ++i) {
|
||||
artifactIds.add(createArtifactForSoftwareModule("file" + i, smId, artifactSize).getId());
|
||||
}
|
||||
assertThat(artifactRepository.findBySoftwareModuleId(PAGE, smId).getTotalElements()).isEqualTo(maxArtifacts);
|
||||
assertThat(artifactManagement.findBySoftwareModule(PAGE, smId).getTotalElements()).isEqualTo(maxArtifacts);
|
||||
|
||||
// create one mode to trigger the quota exceeded error
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
@@ -197,12 +198,12 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// delete one of the artifacts
|
||||
artifactManagement.delete(artifactIds.get(0));
|
||||
assertThat(artifactRepository.findBySoftwareModuleId(PAGE, smId).getTotalElements())
|
||||
assertThat(artifactManagement.findBySoftwareModule(PAGE, smId).getTotalElements())
|
||||
.isEqualTo(maxArtifacts - 1);
|
||||
|
||||
// now we should be able to create an artifact again
|
||||
createArtifactForSoftwareModule("fileXYZ", smId, artifactSize);
|
||||
assertThat(artifactRepository.findBySoftwareModuleId(PAGE, smId).getTotalElements()).isEqualTo(maxArtifacts);
|
||||
assertThat(artifactManagement.findBySoftwareModule(PAGE, smId).getTotalElements()).isEqualTo(maxArtifacts);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -280,7 +281,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,
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -21,6 +21,7 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.AutoConfirmationAlreadyActiveException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -57,7 +57,11 @@ import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
@@ -1191,7 +1195,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
assertThat(actionStatusRepository.count()).isEqualTo(2);
|
||||
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(2);
|
||||
assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(true);
|
||||
assertThat(activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1214,7 +1218,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
assertThat(actionStatusRepository.count()).isEqualTo(2);
|
||||
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(2);
|
||||
assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
|
||||
assertThat(activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1237,7 +1241,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
assertThat(actionStatusRepository.count()).isEqualTo(3);
|
||||
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(3);
|
||||
assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
|
||||
assertThat(activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1261,7 +1265,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
assertThat(actionStatusRepository.count()).isEqualTo(4);
|
||||
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(4);
|
||||
assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
|
||||
assertThat(activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1365,7 +1369,10 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
allActionId.add(actionId);
|
||||
}
|
||||
|
||||
final List<Action> foundAction = controllerManagement.getActiveActionsByExternalRef(allExternalRef);
|
||||
final List<Action> foundAction = actionRepository.findAll((root, query, cb) -> cb.and(
|
||||
root.get(JpaAction_.externalRef).in(allExternalRef),
|
||||
cb.equal(root.get(JpaAction_.active), true)
|
||||
)).stream().map(Action.class::cast).toList();
|
||||
assertThat(foundAction).isNotNull();
|
||||
for (int i = 0; i < numberOfActions; i++) {
|
||||
assertThat(foundAction.get(i).getId()).isEqualTo(allActionId.get(i));
|
||||
@@ -1451,7 +1458,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED));
|
||||
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(status));
|
||||
assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
|
||||
assertThat(activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1549,10 +1556,6 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
private void assertNoActiveActionsExistsForControllerId(final String controllerId) {
|
||||
assertThat(actionRepository.activeActionExistsForControllerId(controllerId)).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Delete a target on requested target deletion from client side")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@@ -1611,8 +1614,16 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
private void assertLastActionStatusCodeInAction(final Long actionId, final Integer expectedLastActionStatusCode) {
|
||||
final Optional<Action> action = actionRepository.getActionById(actionId);
|
||||
final Optional<Action> action = actionRepository.findWithDetailsById(actionId);
|
||||
assertThat(action).isPresent();
|
||||
assertThat(action.get().getLastActionStatusCode()).isEqualTo(Optional.ofNullable(expectedLastActionStatusCode));
|
||||
}
|
||||
|
||||
private void assertNoActiveActionsExistsForControllerId(final String controllerId) {
|
||||
assertThat(activeActionExistsForControllerId(controllerId)).isEqualTo(false);
|
||||
}
|
||||
|
||||
private boolean activeActionExistsForControllerId(final String controllerId) {
|
||||
return actionRepository.exists(ActionSpecifications.byTargetControllerIdAndActive(controllerId, true));
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -52,10 +52,16 @@ import org.eclipse.hawkbit.repository.exception.IncompatibleTargetTypeException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -127,7 +133,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
verifyThrownExceptionBy(() -> deploymentManagement.countActionsByTarget(NOT_EXIST_ID), "Target");
|
||||
verifyThrownExceptionBy(() -> deploymentManagement.countActionsByTarget("xxx", NOT_EXIST_ID), "Target");
|
||||
|
||||
verifyThrownExceptionBy(() -> deploymentManagement.findActionsByDistributionSet(PAGE, NOT_EXIST_IDL),
|
||||
verifyThrownExceptionBy(() -> findActionsByDistributionSet(PAGE, NOT_EXIST_IDL),
|
||||
"DistributionSet");
|
||||
verifyThrownExceptionBy(() -> deploymentManagement.findActionsByTarget(NOT_EXIST_ID, PAGE), "Target");
|
||||
verifyThrownExceptionBy(() -> deploymentManagement.findActionsByTarget("id==*", NOT_EXIST_ID, PAGE), "Target");
|
||||
@@ -429,14 +435,12 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Description("Force Quit an not canceled Assignment. Expected behaviour is that the action can not be force quit and there is thrown an exception.")
|
||||
void forceQuitNotAllowedThrowsException() {
|
||||
final Action action = prepareFinishedUpdate("4712", "installed", true);
|
||||
final Target target = action.getTarget();
|
||||
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("newDS", true);
|
||||
|
||||
// verify initial status
|
||||
assertThat(targetManagement.getByControllerID("4712").get().getUpdateStatus()).as("wrong update status")
|
||||
.isEqualTo(TargetUpdateStatus.IN_SYNC);
|
||||
|
||||
final Target target = action.getTarget();
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("newDS", true);
|
||||
final Action assigningAction = assignSet(target, ds);
|
||||
|
||||
// verify assignment
|
||||
@@ -456,7 +460,12 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId())).as("wrong assigned ds")
|
||||
.contains(ds);
|
||||
final JpaAction action = actionRepository
|
||||
.findByTargetAndDistributionSet(PAGE, (JpaTarget) target, (JpaDistributionSet) ds).getContent().get(0);
|
||||
.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;
|
||||
}
|
||||
@@ -490,7 +499,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
assertThat(actionRepository.count()).isEqualTo(20);
|
||||
assertThat(actionRepository.findByDistributionSetId(PAGE, ds.getId())).as("Offline actions are not active")
|
||||
assertThat(findActionsByDistributionSet(PAGE, ds.getId())).as("Offline actions are not active")
|
||||
.allMatch(action -> !action.isActive()).as("Actions should be initiated by current user")
|
||||
.allMatch(a -> a.getInitiatedBy().equals(tenantAware.getCurrentUsername()));
|
||||
|
||||
@@ -526,7 +535,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
assertThat(getResultingActionCount(assignmentResults)).isEqualTo(4);
|
||||
targetIds.forEach(controllerId -> {
|
||||
final List<Long> assignedDsIds = actionRepository.findByTargetControllerId(PAGE, controllerId).stream()
|
||||
final List<Long> assignedDsIds = deploymentManagement.findActionsByTarget(controllerId, PAGE).stream()
|
||||
.peek(a -> assertThat(a.getInitiatedBy()).as("Actions should be initiated by current user")
|
||||
.isEqualTo(tenantAware.getCurrentUsername()))
|
||||
.map(action -> action.getDistributionSet().getId()).collect(Collectors.toList());
|
||||
@@ -604,7 +613,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
private void assertDsExclusivelyAssignedToTargets(final List<Target> targets, final long dsId, final boolean active,
|
||||
final Status status) {
|
||||
final List<Action> assignment = actionRepository.findByDistributionSetId(PAGE, dsId).getContent();
|
||||
final List<Action> assignment = findActionsByDistributionSet(PAGE, dsId).getContent();
|
||||
final String currentUsername = tenantAware.getCurrentUsername();
|
||||
|
||||
assertThat(assignment).hasSize(10).allMatch(action -> action.isActive() == active)
|
||||
@@ -637,7 +646,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(getResultingActionCount(results)).isEqualTo(deploymentRequests.size());
|
||||
final List<Long> dsIds = distributionSets.stream().map(DistributionSet::getId).collect(Collectors.toList());
|
||||
targets.forEach(target -> {
|
||||
final List<Long> assignedDsIds = actionRepository.findByTargetControllerId(PAGE, target.getControllerId())
|
||||
final List<Long> assignedDsIds = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE)
|
||||
.stream()
|
||||
.peek(a -> assertThat(a.getInitiatedBy()).as("Initiated by current user")
|
||||
.isEqualTo(tenantAware.getCurrentUsername()))
|
||||
@@ -671,7 +680,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final List<Long> dsIds = distributionSets.stream().map(DistributionSet::getId).collect(Collectors.toList());
|
||||
targets.forEach(target -> {
|
||||
actionRepository.findByTargetControllerId(PAGE, target.getControllerId()).forEach(action -> {
|
||||
deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).forEach(action -> {
|
||||
assertThat(action.getDistributionSet().getId()).isIn(dsIds);
|
||||
assertThat(action.getInitiatedBy()).as("Should be Initiated by current user")
|
||||
.isEqualTo(tenantAware.getCurrentUsername());
|
||||
@@ -753,7 +762,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(getResultingActionCount(results)).isEqualTo(controllerIds.size());
|
||||
|
||||
controllerIds.forEach(controllerId -> {
|
||||
actionRepository.findByTargetControllerId(PAGE, controllerId).forEach(action -> {
|
||||
deploymentManagement.findActionsByTarget(controllerId, PAGE).forEach(action -> {
|
||||
assertThat(action.getDistributionSet().getId()).isIn(distributionSet.getId());
|
||||
assertThat(action.getInitiatedBy()).as("Should be Initiated by current user")
|
||||
.isEqualTo(tenantAware.getCurrentUsername());
|
||||
@@ -789,7 +798,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent()).hasSize(1)
|
||||
.allSatisfy(action -> {
|
||||
assertThat(action.getStatus()).isEqualTo(RUNNING);
|
||||
assertThat(actionStatusRepository.getByActionId(PAGE, action.getId())).hasSize(1)
|
||||
assertThat(actionStatusRepository.findByActionId(PAGE, action.getId())).hasSize(1)
|
||||
.allSatisfy(status -> {
|
||||
final JpaActionStatus actionStatus = (JpaActionStatus) status;
|
||||
assertThat(actionStatus.getStatus()).isEqualTo(WAIT_FOR_CONFIRMATION);
|
||||
@@ -839,7 +848,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(action.getStatus()).isEqualTo(Status.WAIT_FOR_CONFIRMATION);
|
||||
});
|
||||
|
||||
final List<Action> actions = actionRepository.findByTargetControllerId(PAGE, target.getControllerId())
|
||||
final List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE)
|
||||
.getContent();
|
||||
assertThat(actions).hasSize(2)
|
||||
.anyMatch(action -> Objects.equals(action.getDistributionSet().getId(), firstDs.getId())
|
||||
@@ -869,7 +878,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(getResultingActionCount(results)).isEqualTo(controllerIds.size());
|
||||
|
||||
controllerIds.forEach(controllerId -> {
|
||||
actionRepository.findByTargetControllerId(PAGE, controllerId).forEach(action -> {
|
||||
deploymentManagement.findActionsByTarget(controllerId, PAGE).forEach(action -> {
|
||||
assertThat(action.getDistributionSet().getId()).isIn(distributionSet.getId());
|
||||
assertThat(action.getInitiatedBy()).as("Should be Initiated by current user")
|
||||
.isEqualTo(tenantAware.getCurrentUsername());
|
||||
@@ -894,10 +903,10 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
|
||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
|
||||
@Expect(type = ActionCreatedEvent.class, count = 3), @Expect(type = TargetUpdatedEvent.class, count = 2),
|
||||
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2),
|
||||
@Expect(type = MultiActionAssignEvent.class, count = 1),
|
||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
||||
void duplicateAssignmentsInRequestAreOnlyRemovedIfMultiassignmentDisabled() {
|
||||
void duplicateAssignmentsInRequestAreRemovedIfMultiassignmentEnabled() {
|
||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
final List<DeploymentRequest> twoEqualAssignments = Collections.nCopies(2,
|
||||
@@ -911,7 +920,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
DeploymentManagement.deploymentRequest(targetId, dsId).setWeight(555).build());
|
||||
|
||||
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignmentsWithWeight)))
|
||||
.isEqualTo(2);
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
private int getResultingActionCount(final List<DistributionSetAssignmentResult> results) {
|
||||
@@ -921,17 +930,25 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
@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),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 21), // max actions per target are 20 for test
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3 * 21),
|
||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
|
||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
||||
void maxActionsPerTargetIsCheckedBeforeAssignmentExecution() {
|
||||
final int maxActions = quotaManagement.getMaxActionsPerTarget();
|
||||
assertThat(maxActions)
|
||||
.as("Expect 20 as maxActionPerTarget. If not the case change @Expect counts for " +
|
||||
"DistributionSetCreatedEvent and SoftwareModuleCreatedEvent accordingly!")
|
||||
.isEqualTo(20);
|
||||
final int size = maxActions + 1;
|
||||
final String controllerId = testdataFactory.createTarget().getControllerId();
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = Collections.nCopies(maxActions + 1,
|
||||
DeploymentManagement.deploymentRequest(controllerId, dsId).setWeight(24).build());
|
||||
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
deploymentRequests.add(
|
||||
DeploymentManagement.deploymentRequest(controllerId, dsId).setWeight(24).build());
|
||||
}
|
||||
|
||||
enableMultiAssignments();
|
||||
Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
@@ -997,8 +1014,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
deploymentManagement.assignDistributionSets(Collections.singletonList(valideRequest1)).get(0)).getId();
|
||||
final Long valideActionId2 = getFirstAssignedAction(
|
||||
deploymentManagement.assignDistributionSets(Collections.singletonList(valideRequest2)).get(0)).getId();
|
||||
assertThat(actionRepository.getActionById(valideActionId1).get().getWeight()).get().isEqualTo(Action.WEIGHT_MAX);
|
||||
assertThat(actionRepository.getActionById(valideActionId2).get().getWeight()).get().isEqualTo(Action.WEIGHT_MIN);
|
||||
assertThat(actionRepository.findWithDetailsById(valideActionId1).get().getWeight()).get().isEqualTo(Action.WEIGHT_MAX);
|
||||
assertThat(actionRepository.findWithDetailsById(valideActionId2).get().getWeight()).get().isEqualTo(Action.WEIGHT_MIN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1174,9 +1191,9 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
final JpaDistributionSet dsC = (JpaDistributionSet) deployResWithDsC.getDistributionSets().get(0);
|
||||
|
||||
// retrieving the UpdateActions created by the assignments
|
||||
actionRepository.findByDistributionSetId(pageRequest, dsA.getId()).getContent().get(0);
|
||||
actionRepository.findByDistributionSetId(pageRequest, dsB.getId()).getContent().get(0);
|
||||
actionRepository.findByDistributionSetId(pageRequest, dsC.getId()).getContent().get(0);
|
||||
findActionsByDistributionSet(pageRequest, dsA.getId()).getContent().get(0);
|
||||
findActionsByDistributionSet(pageRequest, dsB.getId()).getContent().get(0);
|
||||
findActionsByDistributionSet(pageRequest, dsC.getId()).getContent().get(0);
|
||||
|
||||
// verifying the correctness of the assignments
|
||||
for (final Target t : deployResWithDsA.getDeployedTargets()) {
|
||||
@@ -1224,7 +1241,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
// UpdateAction for dsA
|
||||
final List<Target> deployed2DS = assignDistributionSet(dsA, deployResWithDsB.getDeployedTargets())
|
||||
.getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
|
||||
actionRepository.findByDistributionSetId(pageRequest, dsA.getId()).getContent().get(1);
|
||||
findActionsByDistributionSet(pageRequest, dsA.getId()).getContent().get(1);
|
||||
|
||||
// get final updated version of targets
|
||||
final List<Target> deployResWithDsBTargets = targetManagement.getByControllerID(deployResWithDsB
|
||||
@@ -1371,7 +1388,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, targ.getControllerId()).getContent().get(0)
|
||||
.getDistributionSet()).as("Installed distribution set of action should be null").isNotNull();
|
||||
|
||||
final Page<Action> updAct = actionRepository.findByDistributionSetId(PAGE, dsA.getId());
|
||||
final Slice<Action> updAct = findActionsByDistributionSet(PAGE, dsA.getId());
|
||||
controllerManagement.addUpdateActionStatus(
|
||||
entityFactory.actionStatus().create(updAct.getContent().get(0).getId()).status(Status.FINISHED));
|
||||
|
||||
@@ -1676,6 +1693,14 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
private Slice<Action> findActionsByDistributionSet(final Pageable pageable, final long distributionSetId) {
|
||||
distributionSetManagement.get(distributionSetId).orElseThrow(() -> new EntityNotFoundException(
|
||||
DistributionSet.class, distributionSetId));
|
||||
return actionRepository
|
||||
.findAll(ActionSpecifications.byDistributionSetId(distributionSetId), pageable)
|
||||
.map(Action.class::cast);
|
||||
}
|
||||
|
||||
private static class DeploymentResult {
|
||||
final List<Long> deployedTargetIDs = new ArrayList<>();
|
||||
final List<Long> undeployedTargetIDs = new ArrayList<>();
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -18,6 +18,9 @@ import java.util.List;
|
||||
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;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
@@ -35,6 +38,7 @@ 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
|
||||
@@ -69,8 +73,8 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
|
||||
// if status is pending, the assignment has not been canceled
|
||||
assertThat(targetRepository.findById(target.getId()).get().getUpdateStatus())
|
||||
.isEqualTo(TargetUpdateStatus.PENDING);
|
||||
assertThat(actionRepository.findByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(actionRepository.findByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
|
||||
assertThat(findActionsByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(findActionsByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,8 +105,8 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
|
||||
assertThat(
|
||||
targetRepository.findById(invalidationTestData.getTargets().get(0).getId()).get().getUpdateStatus())
|
||||
.isEqualTo(TargetUpdateStatus.PENDING);
|
||||
assertThat(actionRepository.findByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(actionRepository.findByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
|
||||
assertThat(findActionsByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(findActionsByTarget(target).get(0).getStatus()).isEqualTo(Status.RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,8 +135,8 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
|
||||
for (final Target target : invalidationTestData.getTargets()) {
|
||||
assertThat(targetRepository.findById(target.getId()).get().getUpdateStatus())
|
||||
.isEqualTo(TargetUpdateStatus.IN_SYNC);
|
||||
assertThat(actionRepository.findByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(actionRepository.findByTarget(target).get(0).getStatus()).isEqualTo(Status.CANCELED);
|
||||
assertThat(findActionsByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(findActionsByTarget(target).get(0).getStatus()).isEqualTo(Status.CANCELED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +173,8 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
|
||||
for (final Target target : invalidationTestData.getTargets()) {
|
||||
assertThat(targetRepository.findById(target.getId()).get().getUpdateStatus())
|
||||
.isEqualTo(TargetUpdateStatus.PENDING);
|
||||
assertThat(actionRepository.findByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(actionRepository.findByTarget(target).get(0).getStatus()).isEqualTo(Status.CANCELING);
|
||||
assertThat(findActionsByTarget(target).size()).isEqualTo(1);
|
||||
assertThat(findActionsByTarget(target).get(0).getStatus()).isEqualTo(Status.CANCELING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,4 +306,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
|
||||
assertThat(distributionSetInvalidationCount.getRolloutsCount()).isEqualTo(expectedRolloutCount);
|
||||
}
|
||||
|
||||
private List<JpaAction> findActionsByTarget(@Param("target") Target target) { // order by id ?
|
||||
return actionRepository.findAll(ActionSpecifications.byTargetControllerId(target.getControllerId()));
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -42,6 +42,7 @@ import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpda
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -30,6 +30,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdated
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupUpdatedEve
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -58,6 +58,7 @@ import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetExcepti
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -27,9 +27,15 @@ import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.RandomGeneratedInputStream;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
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;
|
||||
@@ -205,9 +211,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
.first().isEqualTo(ah);
|
||||
assertThat(softwareModuleManagement.findByTextAndType(PAGE, ":1.0", appType.getId()).getContent()).hasSize(2);
|
||||
|
||||
// no we search with on entity marked as deleted
|
||||
softwareModuleManagement.delete(
|
||||
softwareModuleRepository.findByAssignedToAndType(PAGE, ds, appType).getContent().get(0).getId());
|
||||
softwareModuleManagement.delete(ah2.getId());
|
||||
|
||||
assertThat(softwareModuleManagement.findByTextAndType(PAGE, ":1.0", appType.getId()).getContent()).hasSize(1);
|
||||
assertThat(softwareModuleManagement.findByTextAndType(PAGE, ":1.0", appType.getId()).getContent().get(0))
|
||||
@@ -221,7 +225,13 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Optional<DistributionSet> assignedDistributionSet = deploymentManagement
|
||||
.getAssignedDistributionSet(target.getControllerId());
|
||||
assertThat(assignedDistributionSet).contains(ds);
|
||||
final Action action = actionRepository.findByTargetAndDistributionSet(PAGE, target, ds).getContent().get(0);
|
||||
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;
|
||||
}
|
||||
@@ -546,31 +556,31 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
// with filter on name, version and module type
|
||||
assertThat(softwareModuleManagement.findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(PAGE,
|
||||
set.getId(), "%found%", testType.getId()).getContent())
|
||||
.as("Found modules with given name, given module type and the assigned ones first")
|
||||
.containsExactly(new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
|
||||
new AssignedSoftwareModule(unassigned, false));
|
||||
.as("Found modules with given name, given module type and the assigned ones first")
|
||||
.containsExactly(new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
|
||||
new AssignedSoftwareModule(unassigned, false));
|
||||
|
||||
// with filter on name, version and module type, sorting defined by
|
||||
// Pagerequest
|
||||
assertThat(softwareModuleManagement.findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(
|
||||
PageRequest.of(0, 500, Sort.by(Direction.DESC, "name")), set.getId(), "%found%", testType.getId())
|
||||
.getContent()).as(
|
||||
"Found modules with given name, given module type, the assigned ones first, ordered by name DESC")
|
||||
.containsExactly(new AssignedSoftwareModule(two, true), new AssignedSoftwareModule(one, true),
|
||||
new AssignedSoftwareModule(unassigned, false));
|
||||
.getContent())
|
||||
.as("Found modules with given name, given module type, the assigned ones first, ordered by name DESC")
|
||||
.containsExactly(new AssignedSoftwareModule(two, true), new AssignedSoftwareModule(one, true),
|
||||
new AssignedSoftwareModule(unassigned, false));
|
||||
|
||||
// with filter on module type only
|
||||
assertThat(softwareModuleManagement
|
||||
.findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(PAGE, set.getId(), null, testType.getId())
|
||||
.getContent()).as("Found modules with given module type and the assigned ones first").containsExactly(
|
||||
new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
|
||||
.getContent()).as("Found modules with given module type and the assigned ones first")
|
||||
.containsExactly(new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
|
||||
new AssignedSoftwareModule(differentName, true), new AssignedSoftwareModule(unassigned, false));
|
||||
|
||||
// without any filter
|
||||
assertThat(softwareModuleManagement
|
||||
.findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(PAGE, set.getId(), null, null)
|
||||
.getContent()).as("Found modules with the assigned ones first").containsExactly(
|
||||
new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
|
||||
.getContent()).as("Found modules with the assigned ones first")
|
||||
.containsExactly(new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
|
||||
new AssignedSoftwareModule(differentName, true), new AssignedSoftwareModule(four, true),
|
||||
new AssignedSoftwareModule(unassigned, false));
|
||||
}
|
||||
@@ -797,22 +807,21 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
final String knownKey1 = "myKnownKey1";
|
||||
final String knownValue1 = "myKnownValue1";
|
||||
|
||||
SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
|
||||
final SoftwareModule swModule = testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
softwareModuleManagement.createMetaData(
|
||||
entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey1).value(knownValue1));
|
||||
entityFactory.softwareModuleMetadata().create(swModule.getId()).key(knownKey1).value(knownValue1));
|
||||
|
||||
ah = softwareModuleManagement.get(ah.getId()).get();
|
||||
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(
|
||||
softwareModuleManagement.findMetaDataBySoftwareModuleId(PageRequest.of(0, 10), ah.getId()).getContent())
|
||||
.as("Contains the created metadata element")
|
||||
.containsExactly(new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue1));
|
||||
|
||||
softwareModuleManagement.deleteMetaData(ah.getId(), knownKey1);
|
||||
assertThat(
|
||||
softwareModuleManagement.findMetaDataBySoftwareModuleId(PageRequest.of(0, 10), ah.getId()).getContent())
|
||||
.as("Metadata elements are").isEmpty();
|
||||
softwareModuleManagement.deleteMetaData(swModule.getId(), knownKey1);
|
||||
assertThat(softwareModuleManagement.findMetaDataBySoftwareModuleId(PageRequest.of(0, 10), swModule.getId())
|
||||
.getContent()).as("Metadata elements are").isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
@@ -20,6 +20,7 @@ import javax.validation.ConstraintViolationException;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -37,6 +37,7 @@ import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeExcep
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -718,7 +719,7 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
assignDistributionSet(assignedSet, assignedTargets);
|
||||
|
||||
final List<Target> result = targetManagement
|
||||
.findByTargetFilterQueryAndNonDSAndCompatible(PAGE, assignedSet.getId(), tfq.getQuery()).getContent();
|
||||
.findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(PAGE, assignedSet.getId(), tfq.getQuery()).getContent();
|
||||
assertThat(result).as("count of targets").hasSize(unassignedTargets.size()).as("contains all targets")
|
||||
.containsAll(unassignedTargets);
|
||||
|
||||
@@ -760,7 +761,7 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
targetType);
|
||||
|
||||
final List<Target> result = targetManagement
|
||||
.findByTargetFilterQueryAndNonDSAndCompatible(PAGE, testDs.getId(), tfq.getQuery()).getContent();
|
||||
.findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(PAGE, testDs.getId(), tfq.getQuery()).getContent();
|
||||
|
||||
assertThat(result).as("count of targets").hasSize(targets.size() + targetWithCompatibleTypes.size())
|
||||
.as("contains all targets").containsAll(targetWithCompatibleTypes).containsAll(targets);
|
||||
@@ -790,7 +791,7 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
testTargets.addAll(targetsWithCompatibleType);
|
||||
|
||||
final List<Target> result = targetManagement
|
||||
.findByTargetFilterQueryAndNonDSAndCompatible(PAGE, testDs.getId(), tfq.getQuery()).getContent();
|
||||
.findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(PAGE, testDs.getId(), tfq.getQuery()).getContent();
|
||||
|
||||
assertThat(result).as("count of targets").hasSize(testTargets.size()).as("contains all compatible targets")
|
||||
.containsExactlyInAnyOrderElementsOf(testTargets).as("does not contain incompatible targets")
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -52,6 +52,7 @@ import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -124,14 +125,14 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
"DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(() -> targetManagement.countByTargetFilterQuery(NOT_EXIST_IDL), "TargetFilterQuery");
|
||||
verifyThrownExceptionBy(() -> targetManagement.countByRsqlAndNonDSAndCompatible(NOT_EXIST_IDL, "name==*"),
|
||||
verifyThrownExceptionBy(() -> targetManagement.countByRsqlAndNonDSAndCompatibleAndUpdatable(NOT_EXIST_IDL, "name==*"),
|
||||
"DistributionSet");
|
||||
|
||||
verifyThrownExceptionBy(() -> targetManagement.deleteByControllerID(NOT_EXIST_ID), "Target");
|
||||
verifyThrownExceptionBy(() -> targetManagement.delete(Collections.singletonList(NOT_EXIST_IDL)), "Target");
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> targetManagement.findByTargetFilterQueryAndNonDSAndCompatible(PAGE, NOT_EXIST_IDL, "name==*"),
|
||||
() -> targetManagement.findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(PAGE, NOT_EXIST_IDL, "name==*"),
|
||||
"DistributionSet");
|
||||
verifyThrownExceptionBy(() -> targetManagement.findByInRolloutGroupWithoutAction(PAGE, NOT_EXIST_IDL),
|
||||
"RolloutGroup");
|
||||
@@ -153,8 +154,8 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
() -> targetManagement.toggleTagAssignment(Collections.singletonList(NOT_EXIST_ID), tag.getName()),
|
||||
"Target");
|
||||
|
||||
verifyThrownExceptionBy(() -> targetManagement.unAssignTag(NOT_EXIST_ID, tag.getId()), "Target");
|
||||
verifyThrownExceptionBy(() -> targetManagement.unAssignTag(target.getControllerId(), NOT_EXIST_IDL),
|
||||
verifyThrownExceptionBy(() -> targetManagement.unassignTag(NOT_EXIST_ID, tag.getId()), "Target");
|
||||
verifyThrownExceptionBy(() -> targetManagement.unassignTag(target.getControllerId(), NOT_EXIST_IDL),
|
||||
"TargetTag");
|
||||
verifyThrownExceptionBy(() -> targetManagement.update(entityFactory.target().update(NOT_EXIST_ID)), "Target");
|
||||
|
||||
@@ -393,7 +394,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(assignedTargets.size()).as("Assigned targets are wrong")
|
||||
.isEqualTo(targetManagement.findByTag(PAGE, targetTag.getId()).getNumberOfElements());
|
||||
|
||||
final Target unAssignTarget = targetManagement.unAssignTag("targetId123", findTargetTag.getId());
|
||||
final Target unAssignTarget = targetManagement.unassignTag("targetId123", findTargetTag.getId());
|
||||
assertThat(unAssignTarget.getControllerId()).as("Controller id is wrong").isEqualTo("targetId123");
|
||||
assertThat(targetTagManagement.findByTarget(PAGE, unAssignTarget.getControllerId())).as("Tag size is wrong")
|
||||
.isEmpty();
|
||||
@@ -1068,7 +1069,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(targetFound1.get().getTargetType().getId()).isEqualTo(targetTypes.get(1).getId());
|
||||
|
||||
// unassign the target type
|
||||
targetManagement.unAssignType(target.getControllerId());
|
||||
targetManagement.unassignType(target.getControllerId());
|
||||
|
||||
// opt lock revision must be changed
|
||||
final Optional<JpaTarget> targetFound2 = targetRepository.findById(target.getId());
|
||||
@@ -1226,7 +1227,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(targetFound.get().getTargetType().getName()).isEqualTo(targetType.getName());
|
||||
|
||||
// un-assign target type from target
|
||||
targetManagement.unAssignType(targetFound.get().getControllerId());
|
||||
targetManagement.unassignType(targetFound.get().getControllerId());
|
||||
|
||||
// opt lock revision must be changed
|
||||
final Optional<JpaTarget> targetFound1 = targetRepository.findById(target.getId());
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -26,6 +26,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpda
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -22,6 +22,7 @@ import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
@@ -18,6 +18,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidTenantConfigurationKeyException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
@@ -102,7 +102,6 @@ public class RSQLSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Test filter software module by name which contain mutated vowels ")
|
||||
@Disabled("Temporarily disabled because test depends on collation settings of database")
|
||||
public void testFilterByParameterNameWithUmlaut() {
|
||||
assertRSQLQuery(SoftwareModuleFields.NAME.name() + "==*Ö*", 1);
|
||||
assertRSQLQuery(SoftwareModuleFields.NAME.name() + "==*Ä*", 1);
|
||||
|
||||
Reference in New Issue
Block a user