diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/test/cust/TestCustomerEntity.java b/src/main/java/net/hostsharing/hsadminng/rbac/test/cust/TestCustomerEntity.java index e9541dd7..72df9c48 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/test/cust/TestCustomerEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/test/cust/TestCustomerEntity.java @@ -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 { @Id diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbDatabaseHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbDatabaseHostingAssetValidatorUnitTest.java index e96694f8..1d9cd8a1 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbDatabaseHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbDatabaseHostingAssetValidatorUnitTest.java @@ -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(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidatorUnitTest.java index 1c818c33..ff882e91 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidatorUnitTest.java @@ -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(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsPostgreSqlDatabaseHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsPostgreSqlDatabaseHostingAssetValidatorUnitTest.java index a74edd5a..b20df86d 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsPostgreSqlDatabaseHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsPostgreSqlDatabaseHostingAssetValidatorUnitTest.java @@ -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(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsPostgreSqlUserHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsPostgreSqlUserHostingAssetValidatorUnitTest.java index 89091fd3..91b38508 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsPostgreSqlUserHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsPostgreSqlUserHostingAssetValidatorUnitTest.java @@ -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(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidatorUnitTest.java index 922ad152..04768707 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidatorUnitTest.java @@ -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(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java index d2960862..a1fccbb9 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java @@ -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 diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationControllerAcceptanceTest.java index 4f397199..265a65e3 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationControllerAcceptanceTest.java @@ -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(); } diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/test/ContextBasedTestWithCleanup.java b/src/test/java/net/hostsharing/hsadminng/rbac/test/ContextBasedTestWithCleanup.java index 5fb1c4e6..8e5f9683 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/test/ContextBasedTestWithCleanup.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/test/ContextBasedTestWithCleanup.java @@ -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 initialRbacObjects; private Set initialRbacRoles; private Set 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()) { - out.println(ContextBasedTestWithCleanup.class.getSimpleName() + ".cleanupAndCheckCleanup"); - cleanupTemporaryTestData(); - repeatUntilTrue(3, this::deleteLeakedRbacObjects); + this.testInfo = testInfo; - long rbacObjectCount = assertNoNewRbacObjectsRolesAndGrantsLeaked(); - out.println("TOTAL OBJECT COUNT (after): " + rbacObjectCount); - } + out.println(ContextBasedTestWithCleanup.class.getSimpleName() + ".cleanupAndCheckCleanup"); + cleanupTemporaryTestData(); + repeatUntilTrue(3, this::deleteLeakedRbacObjects); + + 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 before, final Set after) { assertThat(before).isNotNull(); assertThat(after).isNotNull(); - assertThat(difference(before, after)).as("missing entities (deleted initial test data)").isEmpty(); + final SetUtils.SetView 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(); } diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/test/cust/TestCustomerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/test/cust/TestCustomerRepositoryIntegrationTest.java index 04175d04..831a2976 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/test/cust/TestCustomerRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/test/cust/TestCustomerRepositoryIntegrationTest.java @@ -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}"); }