Fix EntityMatcher when for Identifiable.getId (#2724)
* Fix EntityMatcher to process properly filters of type targetType.id - to resolve correctly the getter return type Long not T * Add AutoAsssignTest access control test * Simplify rest of the ACM tests Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
@TestPropertySource(properties = "hawkbit.acm.access-controller.enabled=true")
|
||||
abstract class AbstractAccessControllerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
protected SoftwareModuleType smType1;
|
||||
protected SoftwareModuleType smType2;
|
||||
protected SoftwareModule sm1Type1;
|
||||
protected SoftwareModule sm2Type2;
|
||||
protected SoftwareModule sm3Type2;
|
||||
|
||||
protected DistributionSetType dsType1;
|
||||
protected DistributionSetType dsType2;
|
||||
protected DistributionSet ds1Type1;
|
||||
protected DistributionSet ds2Type2;
|
||||
protected DistributionSet ds3Type2;
|
||||
|
||||
protected TargetType targetType1;
|
||||
protected TargetType targetType2;
|
||||
protected Target target1Type1;
|
||||
protected Target target2Type2;
|
||||
protected Target target3Type2;
|
||||
|
||||
@BeforeEach
|
||||
@Override
|
||||
public void beforeAll() throws Exception {
|
||||
super.beforeAll();
|
||||
|
||||
smType1 = testdataFactory.findOrCreateSoftwareModuleType("SmType1");
|
||||
smType2 = testdataFactory.findOrCreateSoftwareModuleType("SmType2");
|
||||
sm1Type1 = softwareModuleManagement.lock(testdataFactory.createSoftwareModule(smType1.getKey()));
|
||||
sm2Type2 = softwareModuleManagement.lock(testdataFactory.createSoftwareModule(smType2.getKey()));
|
||||
sm3Type2 = softwareModuleManagement.lock(testdataFactory.createSoftwareModule(smType2.getKey()));
|
||||
|
||||
dsType1 = testdataFactory.findOrCreateDistributionSetType("DsType1", "DistributionSetType-1", List.of(smType1), List.of());
|
||||
dsType2 = testdataFactory.findOrCreateDistributionSetType("DsType2", "DistributionSetType-2", List.of(smType2), List.of(smType1));
|
||||
ds1Type1 = distributionSetManagement.lock(
|
||||
testdataFactory.createDistributionSet("Ds1Type1", "1.0", dsType1, List.of(sm1Type1)));
|
||||
ds2Type2 = distributionSetManagement.lock(
|
||||
testdataFactory.createDistributionSet("Ds2Type2", "1.0", dsType2, List.of(sm2Type2, sm1Type1)));
|
||||
ds3Type2 = distributionSetManagement.lock(
|
||||
testdataFactory.createDistributionSet("Ds3Type2", "1.0", dsType2, List.of(sm3Type2, sm1Type1)));
|
||||
|
||||
targetType1 = testdataFactory.createTargetType("TargetType1", Set.of(dsType1, dsType2));
|
||||
targetType2 = testdataFactory.createTargetType("TargetType2", Set.of(dsType2));
|
||||
target1Type1 = testdataFactory.createTarget("controller_1", "Controller-1", targetType1);
|
||||
target2Type2 = testdataFactory.createTarget("controller_2", "Controller-2", targetType2);
|
||||
target3Type2 = testdataFactory.createTarget("controller_3", "Controller-3", targetType2);
|
||||
}
|
||||
|
||||
protected static WithUser withAuthorities(final String... authorities) {
|
||||
AuthorityChecker.validateAuthorities(authorities);
|
||||
return SecurityContextSwitch.withUser("user", authorities);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.eclipse.hawkbit.security.SecurityContextSerializer;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
class AcmTestConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SecurityContextSerializer securityContextSerializer() {
|
||||
return SecurityContextSerializer.JSON_SERIALIZATION;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
@ContextConfiguration(classes = { AccessControllerConfiguration.class })
|
||||
@TestPropertySource(properties = "hawkbit.acm.access-controller.enabled=true")
|
||||
class ActionAccessControllerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.eclipse.hawkbit.im.authentication.SpPermission.CREATE_TARGET;
|
||||
import static org.eclipse.hawkbit.im.authentication.SpPermission.DELETE_TARGET;
|
||||
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_DISTRIBUTION_SET;
|
||||
import static org.eclipse.hawkbit.im.authentication.SpPermission.READ_TARGET;
|
||||
import static org.eclipse.hawkbit.im.authentication.SpPermission.UPDATE_TARGET;
|
||||
import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.callAs;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.autoassign.AutoAssignScheduler;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.integration.support.locks.LockRegistry;
|
||||
|
||||
class AutoAssignTest extends AbstractAccessControllerTest {
|
||||
|
||||
@Autowired
|
||||
AutoAssignExecutor autoAssignExecutor;
|
||||
|
||||
@Autowired
|
||||
LockRegistry lockRegistry;
|
||||
|
||||
@Test
|
||||
void verifyOnlyUpdatableTargetsArePartOfAutoAssignmentByScheduler() throws Exception {
|
||||
// auto assign scheduler apply stored access control context and the context is correctly applied
|
||||
verifyOnlyUpdatableTargetsArePartOfAutoAssignment(
|
||||
() -> new AutoAssignScheduler(systemManagement, systemSecurityContext, autoAssignExecutor, lockRegistry, Optional.empty())
|
||||
.autoAssignScheduler());
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyOnlyUpdatableTargetsArePartOfAutoAssignment() throws Exception {
|
||||
verifyOnlyUpdatableTargetsArePartOfAutoAssignment(autoAssignExecutor::checkAllTargets);
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyOnlyUpdatableTargetsWillGetAssignmentOnSingleCheck() throws Exception {
|
||||
verifyOnlyUpdatableTargetsArePartOfAutoAssignment(() -> {
|
||||
autoAssignExecutor.checkSingleTarget(target1Type1.getControllerId());
|
||||
autoAssignExecutor.checkSingleTarget(target2Type2.getControllerId());
|
||||
autoAssignExecutor.checkSingleTarget(target3Type2.getControllerId());
|
||||
});
|
||||
}
|
||||
|
||||
private void verifyOnlyUpdatableTargetsArePartOfAutoAssignment(final Runnable assigner) throws Exception {
|
||||
final TargetFilterQuery targetFilterQuery = callAs(withAuthorities(
|
||||
CREATE_TARGET,
|
||||
READ_TARGET + "/controllerid==*",
|
||||
UPDATE_TARGET + "/type.id==" + targetType2.getId(), // only updatable (i.e. of targetType2) shall be assigned
|
||||
DELETE_TARGET + "/type.id==" + targetType1.getId(),
|
||||
READ_DISTRIBUTION_SET + "/type.id==" + dsType2.getId()),
|
||||
() -> {
|
||||
final TargetFilterQuery targetFilter = targetFilterQueryManagement
|
||||
.create(TargetFilterQueryManagement.Create.builder().name("testAutoAssignment").query("controllerid==*").build());
|
||||
return targetFilterQueryManagement.updateAutoAssignDS(
|
||||
new AutoAssignDistributionSetUpdate(targetFilter.getId()).ds(ds2Type2.getId()));
|
||||
});
|
||||
|
||||
// do the assignment
|
||||
assigner.run();
|
||||
|
||||
assertThat(targetManagement.findByAssignedDistributionSet(targetFilterQuery.getAutoAssignDistributionSet().getId(), Pageable.unpaged())
|
||||
.map(Identifiable::getId).toList())
|
||||
.as("Only updatable targets should be part of the rollout")
|
||||
// all targets are distribution set type 2 compatible, but since user has UPDATE_TARGET only for targets of type 2
|
||||
// only target2 and target3 shall be assigned
|
||||
.containsExactly(target2Type2.getId(), target3Type2.getId());
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
@@ -26,11 +26,15 @@ 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.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||
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.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
@@ -43,10 +47,10 @@ import org.springframework.test.context.ContextConfiguration;
|
||||
* Feature: Component Tests - Context runner<br/>
|
||||
* Story: Test Context Runner
|
||||
*/
|
||||
@ContextConfiguration(classes = { AcmTestConfiguration.class })
|
||||
@ContextConfiguration(classes = { ContextAwareTest.TestConfiguration.class })
|
||||
class ContextAwareTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
private static final List<String> AUTHORITIES = SpPermission.getAllAuthorities();
|
||||
private static final Set<String> AUTHORITIES = SpPermission.getAllAuthorities();
|
||||
|
||||
@Autowired
|
||||
AutoAssignExecutor autoAssignExecutor;
|
||||
@@ -169,4 +173,14 @@ class ContextAwareTest extends AbstractJpaIntegrationTest {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SecurityContextSerializer securityContextSerializer() {
|
||||
return SecurityContextSerializer.JSON_SERIALIZATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,6 @@ import org.springframework.test.context.TestPropertySource;
|
||||
* Feature: Component Tests - Access Control<br/>
|
||||
* Story: Test Distribution Set Access Controller
|
||||
*/
|
||||
@ContextConfiguration(classes = { AccessControllerConfiguration.class })
|
||||
@TestPropertySource(properties = "hawkbit.acm.access-controller.enabled=true")
|
||||
class DistributionSetAccessControllerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
|
||||
@@ -43,14 +43,12 @@ 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 org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
/**
|
||||
* Feature: Component Tests - Access Control<br/>
|
||||
* Story: Test Target Access Controller
|
||||
*/
|
||||
@ContextConfiguration(classes = { AccessControllerConfiguration.class, AcmTestConfiguration.class })
|
||||
@TestPropertySource(properties = "hawkbit.acm.access-controller.enabled=true")
|
||||
class TargetAccessControllerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@@ -185,7 +183,7 @@ class TargetAccessControllerTest extends AbstractJpaIntegrationTest {
|
||||
*/
|
||||
@Test
|
||||
void verifyTargetAssignment() {
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("myDs");
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("myDs");
|
||||
distributionSetManagement.lock(ds);
|
||||
|
||||
final Target permittedTarget = targetManagement
|
||||
|
||||
@@ -30,14 +30,12 @@ import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
/**
|
||||
* Feature: Component Tests - Access Control<br/>
|
||||
* Story: Test Target Type Access Controller
|
||||
*/
|
||||
@ContextConfiguration(classes = { AccessControllerConfiguration.class })
|
||||
@TestPropertySource(properties = "hawkbit.acm.access-controller.enabled=true")
|
||||
class TargetTypeAccessControllerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user