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
+ &lt;repo type&gt;AccessControl classes removed and replaced with
  AccessControl &lt;repo type&gt; 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:
Avgustin Marinov
2023-11-16 11:07:06 +02:00
committed by GitHub
parent 8d487fde33
commit b982039a74
170 changed files with 5371 additions and 3227 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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));
}
}

View File

@@ -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;
}
}

View File

@@ -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()));
}
}

View File

@@ -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()));
}
}

View File

@@ -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()));
}
}

View File

@@ -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) {}
}

View File

@@ -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);
}
}

View File

@@ -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() {

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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));
}
}

View File

@@ -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<>();

View File

@@ -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()));
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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")

View File

@@ -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());

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);