real rbac-entities in booking+hosting #89

Merged
hsh-michaelhoennig merged 15 commits from real-and-rbac-entities-everywhere into master 2024-08-21 06:18:38 +02:00
10 changed files with 66 additions and 46 deletions
Showing only changes of commit e7f26b0f9d - Show all commits

View File

@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import net.hostsharing.hsadminng.rbac.rbacobject.BaseEntity;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
@ -24,6 +25,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class TestCustomerEntity implements BaseEntity<TestCustomerEntity> {
@Id

View File

@ -1,13 +1,13 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.EntityManagerMock;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRbacEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity;
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import jakarta.persistence.EntityManager;
import java.util.HashMap;
import java.util.stream.Stream;
@ -41,9 +41,6 @@ class HsMariaDbDatabaseHostingAssetValidatorUnitTest {
)))
.build();
@Mock
private EntityManager em;
private static HsHostingAssetRbacEntity.HsHostingAssetRbacEntityBuilder givenValidMariaDbDatabaseBuilder() {
return HsHostingAssetRbacEntity.builder()
.type(MARIADB_DATABASE)
@ -74,12 +71,13 @@ class HsMariaDbDatabaseHostingAssetValidatorUnitTest {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbDatabaseBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
final var em = EntityManagerMock.createEntityManagerMockWithAssetQueryFake(null);
// when
final var result = Stream.concat(
final var result = HsEntityValidator.doWithEntityManager(em, () -> Stream.concat(
validator.validateEntity(givenMariaDbUserHostingAsset).stream(),
validator.validateContext(givenMariaDbUserHostingAsset).stream()
).toList();
).toList());
// then
assertThat(result).isEmpty();

View File

@ -1,7 +1,9 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.EntityManagerMock;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRbacEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity;
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
@ -79,12 +81,13 @@ class HsMariaDbUserHostingAssetValidatorUnitTest {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbUserBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
final var em = EntityManagerMock.createEntityManagerMockWithAssetQueryFake(null);
// when
final var result = Stream.concat(
final var result = HsEntityValidator.doWithEntityManager(em, () -> Stream.concat(
validator.validateEntity(givenMariaDbUserHostingAsset).stream(),
validator.validateContext(givenMariaDbUserHostingAsset).stream()
).toList();
).toList());
// then
assertThat(result).isEmpty();

View File

@ -2,8 +2,10 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.EntityManagerMock;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRbacEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity;
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
@ -71,12 +73,13 @@ class HsPostgreSqlDatabaseHostingAssetValidatorUnitTest {
// given
final var givenPgSqlUserHostingAsset = givenValidPgSqlDatabaseBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenPgSqlUserHostingAsset.getType());
final var em = EntityManagerMock.createEntityManagerMockWithAssetQueryFake(null);
// when
final var result = Stream.concat(
final var result = HsEntityValidator.doWithEntityManager(em, () -> Stream.concat(
validator.validateEntity(givenPgSqlUserHostingAsset).stream(),
validator.validateContext(givenPgSqlUserHostingAsset).stream()
).toList();
).toList());
// then
assertThat(result).isEmpty();

View File

@ -1,8 +1,10 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hash.HashGenerator;
import net.hostsharing.hsadminng.hs.hosting.asset.EntityManagerMock;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRbacEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity;
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
import org.junit.jupiter.api.Test;
import jakarta.persistence.EntityManager;
@ -77,12 +79,13 @@ class HsPostgreSqlUserHostingAssetValidatorUnitTest {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbUserBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
final var em = EntityManagerMock.createEntityManagerMockWithAssetQueryFake(null);
// when
final var result = Stream.concat(
final var result = HsEntityValidator.doWithEntityManager(em, () -> Stream.concat(
validator.validateEntity(givenMariaDbUserHostingAsset).stream(),
validator.validateContext(givenMariaDbUserHostingAsset).stream()
).toList();
).toList());
// then
assertThat(result).isEmpty();

View File

@ -1,9 +1,11 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hash.HashGenerator;
import net.hostsharing.hsadminng.hs.hosting.asset.EntityManagerMock;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRbacEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -96,12 +98,13 @@ class HsUnixUserHostingAssetValidatorUnitTest {
// given
final var unixUserHostingAsset = GIVEN_VALID_UNIX_USER_HOSTING_ASSET;
final var validator = HostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
final var em = EntityManagerMock.createEntityManagerMockWithAssetQueryFake(null);
// when
final var result = Stream.concat(
final var result = HsEntityValidator.doWithEntityManager(em, () -> Stream.concat(
validator.validateEntity(unixUserHostingAsset).stream(),
validator.validateContext(unixUserHostingAsset).stream()
).toList();
).toList());
// then
assertThat(result).isEmpty();

View File

@ -140,7 +140,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
});
// then
result.assertExceptionWithRootCauseMessage(org.hibernate.exception.ConstraintViolationException.class);
result.assertExceptionWithRootCauseMessage(org.hibernate.exception.ConstraintViolationException.class,
"ERROR: new row for relation \"hs_office_debitor\" violates check constraint \"check_default_prefix\"");
}
@Test

View File

@ -161,7 +161,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
.extract().header("Location"); // @formatter:on
// finally, the new relation can be accessed under the generated UUID
final var newUserUuid = toCleanup(HsOfficeRelation.class, UUID.fromString(
final var newUserUuid = toCleanup(HsOfficeRelationRealEntity.class, UUID.fromString(
location.substring(location.lastIndexOf('/') + 1)));
assertThat(newUserUuid).isNotNull();
}

View File

@ -7,6 +7,7 @@ import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantRepository;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleEntity;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRepository;
import org.apache.commons.collections4.SetUtils;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@ -56,9 +57,10 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
private static Long latestIntialTestDataSerialId;
private static boolean countersInitialized = false;
private static boolean initialTestDataValidated = false;
private static Long initialRbacObjectCount = null;
private static Long initialRbacRoleCount = null;
private static Long initialRbacGrantCount = null;
static private Long previousRbacObjectCount;
private Long initialRbacObjectCount = null;
private Long initialRbacRoleCount = null;
private Long initialRbacGrantCount = null;
private Set<String> initialRbacObjects;
private Set<String> initialRbacRoles;
private Set<String> initialRbacGrants;
@ -120,6 +122,7 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
@BeforeEach
//@Transactional -- TODO: check why this does not work but jpaAttempt.transacted does work
void retrieveInitialTestData(final TestInfo testInfo) {
this.testInfo = testInfo;
out.println(ContextBasedTestWithCleanup.class.getSimpleName() + ".retrieveInitialTestData");
if (latestIntialTestDataSerialId == null ) {
@ -127,7 +130,7 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
}
if (initialRbacObjects != null){
assertNoNewRbacObjectsRolesAndGrantsLeaked();
assertNoNewRbacObjectsRolesAndGrantsLeaked("before");
}
initialTestDataValidated = false;
@ -157,7 +160,10 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
assertThat(countersInitialized).as("error while retrieving initial test data").isTrue();
assertThat(initialTestDataValidated).as("check previous test for leaked test data").isTrue();
out.println("TOTAL OBJECT COUNT (before): " + initialRbacObjectCount);
out.println(testInfo.getDisplayName() + ": TOTAL OBJECT COUNT (initial): " + previousRbacObjectCount + " -> " + initialRbacObjectCount);
if (previousRbacObjectCount != null) {
assertThat(initialRbacObjectCount).as("TOTAL OBJECT COUNT changed from " + previousRbacObjectCount + " to " + initialRbacObjectCount).isEqualTo(previousRbacObjectCount);
}
}
private Long assumeSameInitialCount(final Long countBefore, final long currentCount, final String name) {
@ -167,23 +173,15 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
return currentCount;
}
@BeforeEach
void keepTestInfo(final TestInfo testInfo) {
this.testInfo = testInfo;
}
@AfterEach
void cleanupAndCheckCleanup(final TestInfo testInfo) {
// If the whole test method has its own transaction, cleanup makes no sense.
// If that transaction even failed, cleaunup would cause an exception.
if (!tm.getTransaction(null).isRollbackOnly()) {
this.testInfo = testInfo;
out.println(ContextBasedTestWithCleanup.class.getSimpleName() + ".cleanupAndCheckCleanup");
cleanupTemporaryTestData();
repeatUntilTrue(3, this::deleteLeakedRbacObjects);
long rbacObjectCount = assertNoNewRbacObjectsRolesAndGrantsLeaked();
out.println("TOTAL OBJECT COUNT (after): " + rbacObjectCount);
}
assertNoNewRbacObjectsRolesAndGrantsLeaked("after");
}
private void cleanupTemporaryTestData() {
@ -208,8 +206,8 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
}
}
private long assertNoNewRbacObjectsRolesAndGrantsLeaked() {
return jpaAttempt.transacted(() -> {
private void assertNoNewRbacObjectsRolesAndGrantsLeaked(final String event) {
long rbacObjectCount = jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net");
assertEqual(initialRbacObjects, allRbacObjects());
if (DETAILED_BUT_SLOW_CHECK) {
@ -219,21 +217,27 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
// The detailed check works with sets, thus it cannot determine duplicates.
// Therefore, we always compare the counts as well.
long rbacObjectCount = 0;
assertThat(rbacObjectCount = rbacObjectRepo.count()).as("not all business objects got cleaned up (by current test)")
long count = rbacObjectRepo.count();
out.println(testInfo.getDisplayName() + ": TOTAL OBJECT COUNT (" + event+ "): " + previousRbacObjectCount+ " -> " + count);
assertThat(count).as("not all business objects got cleaned up (by current test)")
.isEqualTo(initialRbacObjectCount);
assertThat(rbacRoleRepo.count()).as("not all rbac roles got cleaned up (by current test)")
.isEqualTo(initialRbacRoleCount);
assertThat(rbacGrantRepo.count()).as("not all rbac grants got cleaned up (by current test)")
.isEqualTo(initialRbacGrantCount);
return rbacObjectCount;
return count;
}).assertSuccessful().returnedValue();
if (previousRbacObjectCount != null) {
assertThat(rbacObjectCount).as("TOTAL OBJECT COUNT changed from " + previousRbacObjectCount + " to " + rbacObjectCount).isEqualTo(previousRbacObjectCount);
}
previousRbacObjectCount = rbacObjectCount;
}
private boolean deleteLeakedRbacObjects() {
final var deletionSuccessful = new AtomicBoolean(true);
rbacObjectRepo.findAll().stream()
.filter(o -> o.serialId > latestIntialTestDataSerialId)
jpaAttempt.transacted(() -> rbacObjectRepo.findAll()).assertSuccessful().returnedValue().stream()
.filter(o -> latestIntialTestDataSerialId != null && o.serialId > latestIntialTestDataSerialId)
.sorted(comparing(o -> o.serialId))
.forEach(o -> {
final var exception = jpaAttempt.transacted(() -> {
@ -257,7 +261,8 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
private void assertEqual(final Set<String> before, final Set<String> after) {
assertThat(before).isNotNull();
assertThat(after).isNotNull();
assertThat(difference(before, after)).as("missing entities (deleted initial test data)").isEmpty();
final SetUtils.SetView<String> difference = difference(before, after);
assertThat(difference).as("missing entities (deleted initial test data)").isEmpty();
assertThat(difference(after, before)).as("spurious entities (test data not cleaned up by this test)").isEmpty();
}

View File

@ -66,7 +66,8 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
"ERROR: [403] insert into test_customer not allowed for current subjects {test_customer#xxx:ADMIN}");
"ERROR: [403] insert into test_customer ",
"not allowed for current subjects {test_customer#xxx:ADMIN}");
}
@Test
@ -84,7 +85,8 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
"ERROR: [403] insert into test_customer not allowed for current subjects {customer-admin@xxx.example.com}");
"ERROR: [403] insert into test_customer ",
" not allowed for current subjects {customer-admin@xxx.example.com}");
}