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

View File

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

View File

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

View File

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

View File

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

View File

@ -140,7 +140,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
}); });
// then // 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 @Test

View File

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