fixes HTTP GET with multiple values in result array

This commit is contained in:
Michael Hoennig 2024-10-29 09:17:21 +01:00
parent 765b679042
commit 8fc81d8e2b
17 changed files with 161 additions and 73 deletions

View File

@ -84,7 +84,8 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
"ERROR: [400] debitorRel.mark must be null"); "ERROR: [400] debitorRel.mark must be null");
final var entityToSave = mapper.map(body, HsOfficeDebitorEntity.class); final var entityToSave = mapper.map(body, HsOfficeDebitorEntity.class);
if ( body.getDebitorRel() != null ) { try {
if (body.getDebitorRel() != null) {
body.getDebitorRel().setType(DEBITOR.name()); body.getDebitorRel().setType(DEBITOR.name());
final var debitorRel = mapper.map("debitorRel.", body.getDebitorRel(), HsOfficeRelationRealEntity.class); final var debitorRel = mapper.map("debitorRel.", body.getDebitorRel(), HsOfficeRelationRealEntity.class);
entityValidator.validateEntityExists("debitorRel.anchorUuid", debitorRel.getAnchor()); entityValidator.validateEntityExists("debitorRel.anchorUuid", debitorRel.getAnchor());
@ -95,9 +96,28 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
final var debitorRelOptional = relrealRepo.findByUuid(body.getDebitorRelUuid()); final var debitorRelOptional = relrealRepo.findByUuid(body.getDebitorRelUuid());
debitorRelOptional.ifPresentOrElse( debitorRelOptional.ifPresentOrElse(
debitorRel -> {entityToSave.setDebitorRel(relrealRepo.save(debitorRel));}, debitorRel -> {entityToSave.setDebitorRel(relrealRepo.save(debitorRel));},
() -> { throw new ValidationException("Unable to find RealRelation by debitorRelUuid: " + body.getDebitorRelUuid());}); () -> {
throw new ValidationException(
"Unable to find RealRelation by debitorRelUuid: " + body.getDebitorRelUuid());
});
} }
final var partnerRel = em.createNativeQuery("""
SELECT partnerRel.*
FROM hs_office.relation AS partnerRel
JOIN hs_office.relation AS debitorRel
ON debitorRel.type = 'DEBITOR' AND debitorRel.anchorUuid = partnerRel.holderUuid
WHERE partnerRel.type = 'PARTNER'
AND :NEW_DebitorRelUuid = debitorRel.uuid
""").setParameter("NEW_DebitorRelUuid", entityToSave.getDebitorRel().getUuid()).getResultList();
final var debitorRel = em.createNativeQuery("""
SELECT debitorRel.*
FROM hs_office.relation AS debitorRel
WHERE :NEW_DebitorRelUuid = debitorRel.uuid
""").setParameter("NEW_DebitorRelUuid", entityToSave.getDebitorRel().getUuid()).getResultList();
final var savedEntity = debitorRepo.save(entityToSave); final var savedEntity = debitorRepo.save(entityToSave);
em.flush(); em.flush();
em.refresh(savedEntity); em.refresh(savedEntity);
@ -109,6 +129,9 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
.toUri(); .toUri();
final var mapped = mapper.map(savedEntity, HsOfficeDebitorResource.class); final var mapped = mapper.map(savedEntity, HsOfficeDebitorResource.class);
return ResponseEntity.created(uri).body(mapped); return ResponseEntity.created(uri).body(mapped);
} catch (final RuntimeException exc) {
throw exc;
}
} }
@Override @Override

View File

@ -1,5 +1,6 @@
package net.hostsharing.hsadminng.reflection; package net.hostsharing.hsadminng.reflection;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
@ -11,12 +12,12 @@ import static java.util.Optional.empty;
@UtilityClass @UtilityClass
public class AnnotationFinder { public class AnnotationFinder {
@SneakyThrows
public static <T extends Annotation> Optional<T> findCallerAnnotation( public static <T extends Annotation> Optional<T> findCallerAnnotation(
final Class<T> annotationClassToFind, final Class<T> annotationClassToFind,
final Class<? extends Annotation> annotationClassToStopLookup final Class<? extends Annotation> annotationClassToStopLookup
) { ) {
for (var element : Thread.currentThread().getStackTrace()) { for (var element : Thread.currentThread().getStackTrace()) {
try {
final var clazz = Class.forName(element.getClassName()); final var clazz = Class.forName(element.getClassName());
final var method = getMethodFromStackElement(clazz, element); final var method = getMethodFromStackElement(clazz, element);
@ -28,15 +29,11 @@ public class AnnotationFinder {
return empty(); return empty();
} }
} }
} catch (final ClassNotFoundException | NoSuchMethodException e) {
throw new RuntimeException(e); // FIXME: when does this happen?
}
} }
return empty(); return empty();
} }
private static Method getMethodFromStackElement(Class<?> clazz, StackTraceElement element) private static Method getMethodFromStackElement(Class<?> clazz, StackTraceElement element) {
throws NoSuchMethodException {
for (var method : clazz.getDeclaredMethods()) { for (var method : clazz.getDeclaredMethods()) {
if (method.getName().equals(element.getMethodName())) { if (method.getName().equals(element.getMethodName())) {
return method; return method;

View File

@ -36,7 +36,7 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM rbactest.customer WHERE uuid = NEW.customerUuid INTO newCustomer; SELECT * FROM rbactest.customer WHERE uuid = NEW.customerUuid INTO newCustomer;
assert newCustomer.uuid is not null, format('newCustomer must not be null for NEW.customerUuid = %s', NEW.customerUuid); assert newCustomer.uuid is not null, format('newCustomer must not be null for NEW.customerUuid = %s of package', NEW.customerUuid);
perform rbac.defineRoleWithGrants( perform rbac.defineRoleWithGrants(
@ -102,10 +102,10 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM rbactest.customer WHERE uuid = OLD.customerUuid INTO oldCustomer; SELECT * FROM rbactest.customer WHERE uuid = OLD.customerUuid INTO oldCustomer;
assert oldCustomer.uuid is not null, format('oldCustomer must not be null for OLD.customerUuid = %s', OLD.customerUuid); assert oldCustomer.uuid is not null, format('oldCustomer must not be null for OLD.customerUuid = %s of package', OLD.customerUuid);
SELECT * FROM rbactest.customer WHERE uuid = NEW.customerUuid INTO newCustomer; SELECT * FROM rbactest.customer WHERE uuid = NEW.customerUuid INTO newCustomer;
assert newCustomer.uuid is not null, format('newCustomer must not be null for NEW.customerUuid = %s', NEW.customerUuid); assert newCustomer.uuid is not null, format('newCustomer must not be null for NEW.customerUuid = %s of package', NEW.customerUuid);
if NEW.customerUuid <> OLD.customerUuid then if NEW.customerUuid <> OLD.customerUuid then

View File

@ -36,7 +36,7 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM rbactest.package WHERE uuid = NEW.packageUuid INTO newPackage; SELECT * FROM rbactest.package WHERE uuid = NEW.packageUuid INTO newPackage;
assert newPackage.uuid is not null, format('newPackage must not be null for NEW.packageUuid = %s', NEW.packageUuid); assert newPackage.uuid is not null, format('newPackage must not be null for NEW.packageUuid = %s of domain', NEW.packageUuid);
perform rbac.defineRoleWithGrants( perform rbac.defineRoleWithGrants(
@ -98,10 +98,10 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM rbactest.package WHERE uuid = OLD.packageUuid INTO oldPackage; SELECT * FROM rbactest.package WHERE uuid = OLD.packageUuid INTO oldPackage;
assert oldPackage.uuid is not null, format('oldPackage must not be null for OLD.packageUuid = %s', OLD.packageUuid); assert oldPackage.uuid is not null, format('oldPackage must not be null for OLD.packageUuid = %s of domain', OLD.packageUuid);
SELECT * FROM rbactest.package WHERE uuid = NEW.packageUuid INTO newPackage; SELECT * FROM rbactest.package WHERE uuid = NEW.packageUuid INTO newPackage;
assert newPackage.uuid is not null, format('newPackage must not be null for NEW.packageUuid = %s', NEW.packageUuid); assert newPackage.uuid is not null, format('newPackage must not be null for NEW.packageUuid = %s of domain', NEW.packageUuid);
if NEW.packageUuid <> OLD.packageUuid then if NEW.packageUuid <> OLD.packageUuid then

View File

@ -38,13 +38,13 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM hs_office.person WHERE uuid = NEW.holderUuid INTO newHolderPerson; SELECT * FROM hs_office.person WHERE uuid = NEW.holderUuid INTO newHolderPerson;
assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.holderUuid = %s', NEW.holderUuid); assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.holderUuid = %s of relation', NEW.holderUuid);
SELECT * FROM hs_office.person WHERE uuid = NEW.anchorUuid INTO newAnchorPerson; SELECT * FROM hs_office.person WHERE uuid = NEW.anchorUuid INTO newAnchorPerson;
assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.anchorUuid = %s', NEW.anchorUuid); assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.anchorUuid = %s of relation', NEW.anchorUuid);
SELECT * FROM hs_office.contact WHERE uuid = NEW.contactUuid INTO newContact; SELECT * FROM hs_office.contact WHERE uuid = NEW.contactUuid INTO newContact;
assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid); assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s of relation', NEW.contactUuid);
perform rbac.defineRoleWithGrants( perform rbac.defineRoleWithGrants(

View File

@ -37,10 +37,10 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM hs_office.relation WHERE uuid = NEW.partnerRelUuid INTO newPartnerRel; SELECT * FROM hs_office.relation WHERE uuid = NEW.partnerRelUuid INTO newPartnerRel;
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid); assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s of partner', NEW.partnerRelUuid);
SELECT * FROM hs_office.partner_details WHERE uuid = NEW.detailsUuid INTO newPartnerDetails; SELECT * FROM hs_office.partner_details WHERE uuid = NEW.detailsUuid INTO newPartnerDetails;
assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s', NEW.detailsUuid); assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s of partner', NEW.detailsUuid);
call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'DELETE'), hs_office.relation_OWNER(newPartnerRel)); call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'DELETE'), hs_office.relation_OWNER(newPartnerRel));
call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'SELECT'), hs_office.relation_TENANT(newPartnerRel)); call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'SELECT'), hs_office.relation_TENANT(newPartnerRel));
@ -96,16 +96,16 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM hs_office.relation WHERE uuid = OLD.partnerRelUuid INTO oldPartnerRel; SELECT * FROM hs_office.relation WHERE uuid = OLD.partnerRelUuid INTO oldPartnerRel;
assert oldPartnerRel.uuid is not null, format('oldPartnerRel must not be null for OLD.partnerRelUuid = %s', OLD.partnerRelUuid); assert oldPartnerRel.uuid is not null, format('oldPartnerRel must not be null for OLD.partnerRelUuid = %s of partner', OLD.partnerRelUuid);
SELECT * FROM hs_office.relation WHERE uuid = NEW.partnerRelUuid INTO newPartnerRel; SELECT * FROM hs_office.relation WHERE uuid = NEW.partnerRelUuid INTO newPartnerRel;
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid); assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s of partner', NEW.partnerRelUuid);
SELECT * FROM hs_office.partner_details WHERE uuid = OLD.detailsUuid INTO oldPartnerDetails; SELECT * FROM hs_office.partner_details WHERE uuid = OLD.detailsUuid INTO oldPartnerDetails;
assert oldPartnerDetails.uuid is not null, format('oldPartnerDetails must not be null for OLD.detailsUuid = %s', OLD.detailsUuid); assert oldPartnerDetails.uuid is not null, format('oldPartnerDetails must not be null for OLD.detailsUuid = %s of partner', OLD.detailsUuid);
SELECT * FROM hs_office.partner_details WHERE uuid = NEW.detailsUuid INTO newPartnerDetails; SELECT * FROM hs_office.partner_details WHERE uuid = NEW.detailsUuid INTO newPartnerDetails;
assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s', NEW.detailsUuid); assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s of partner', NEW.detailsUuid);
if NEW.partnerRelUuid <> OLD.partnerRelUuid then if NEW.partnerRelUuid <> OLD.partnerRelUuid then

View File

@ -44,10 +44,10 @@ begin
WHERE partnerRel.type = 'PARTNER' WHERE partnerRel.type = 'PARTNER'
AND NEW.debitorRelUuid = debitorRel.uuid AND NEW.debitorRelUuid = debitorRel.uuid
INTO newPartnerRel; INTO newPartnerRel;
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.debitorRelUuid = %s', NEW.debitorRelUuid); assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.debitorRelUuid = %s of debitor', NEW.debitorRelUuid);
SELECT * FROM hs_office.relation WHERE uuid = NEW.debitorRelUuid INTO newDebitorRel; SELECT * FROM hs_office.relation WHERE uuid = NEW.debitorRelUuid INTO newDebitorRel;
assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorRelUuid = %s', NEW.debitorRelUuid); assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorRelUuid = %s of debitor', NEW.debitorRelUuid);
SELECT * FROM hs_office.bankaccount WHERE uuid = NEW.refundBankAccountUuid INTO newRefundBankAccount; SELECT * FROM hs_office.bankaccount WHERE uuid = NEW.refundBankAccountUuid INTO newRefundBankAccount;

View File

@ -37,14 +37,14 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM hs_office.bankaccount WHERE uuid = NEW.bankAccountUuid INTO newBankAccount; SELECT * FROM hs_office.bankaccount WHERE uuid = NEW.bankAccountUuid INTO newBankAccount;
assert newBankAccount.uuid is not null, format('newBankAccount must not be null for NEW.bankAccountUuid = %s', NEW.bankAccountUuid); assert newBankAccount.uuid is not null, format('newBankAccount must not be null for NEW.bankAccountUuid = %s of sepamandate', NEW.bankAccountUuid);
SELECT debitorRel.* SELECT debitorRel.*
FROM hs_office.relation debitorRel FROM hs_office.relation debitorRel
JOIN hs_office.debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid JOIN hs_office.debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid
WHERE debitor.uuid = NEW.debitorUuid WHERE debitor.uuid = NEW.debitorUuid
INTO newDebitorRel; INTO newDebitorRel;
assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorUuid = %s', NEW.debitorUuid); assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorUuid = %s of sepamandate', NEW.debitorUuid);
perform rbac.defineRoleWithGrants( perform rbac.defineRoleWithGrants(

View File

@ -40,7 +40,7 @@ begin
JOIN hs_office.relation AS partnerRel ON partnerRel.uuid = partner.partnerRelUuid JOIN hs_office.relation AS partnerRel ON partnerRel.uuid = partner.partnerRelUuid
WHERE partner.uuid = NEW.partnerUuid WHERE partner.uuid = NEW.partnerUuid
INTO newPartnerRel; INTO newPartnerRel;
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerUuid = %s', NEW.partnerUuid); assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerUuid = %s of membership', NEW.partnerUuid);
perform rbac.defineRoleWithGrants( perform rbac.defineRoleWithGrants(

View File

@ -36,7 +36,7 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM hs_office.membership WHERE uuid = NEW.membershipUuid INTO newMembership; SELECT * FROM hs_office.membership WHERE uuid = NEW.membershipUuid INTO newMembership;
assert newMembership.uuid is not null, format('newMembership must not be null for NEW.membershipUuid = %s', NEW.membershipUuid); assert newMembership.uuid is not null, format('newMembership must not be null for NEW.membershipUuid = %s of coopshares', NEW.membershipUuid);
call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'SELECT'), hs_office.membership_AGENT(newMembership)); call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'SELECT'), hs_office.membership_AGENT(newMembership));
call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'UPDATE'), hs_office.membership_ADMIN(newMembership)); call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'UPDATE'), hs_office.membership_ADMIN(newMembership));

View File

@ -36,7 +36,7 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM hs_office.membership WHERE uuid = NEW.membershipUuid INTO newMembership; SELECT * FROM hs_office.membership WHERE uuid = NEW.membershipUuid INTO newMembership;
assert newMembership.uuid is not null, format('newMembership must not be null for NEW.membershipUuid = %s', NEW.membershipUuid); assert newMembership.uuid is not null, format('newMembership must not be null for NEW.membershipUuid = %s of coopasset', NEW.membershipUuid);
call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'SELECT'), hs_office.membership_AGENT(newMembership)); call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'SELECT'), hs_office.membership_AGENT(newMembership));
call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'UPDATE'), hs_office.membership_ADMIN(newMembership)); call rbac.grantPermissionToRole(rbac.createPermission(NEW.uuid, 'UPDATE'), hs_office.membership_ADMIN(newMembership));

View File

@ -37,14 +37,14 @@ begin
call rbac.enterTriggerForObjectUuid(NEW.uuid); call rbac.enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM hs_office.debitor WHERE uuid = NEW.debitorUuid INTO newDebitor; SELECT * FROM hs_office.debitor WHERE uuid = NEW.debitorUuid INTO newDebitor;
assert newDebitor.uuid is not null, format('newDebitor must not be null for NEW.debitorUuid = %s', NEW.debitorUuid); assert newDebitor.uuid is not null, format('newDebitor must not be null for NEW.debitorUuid = %s of project', NEW.debitorUuid);
SELECT debitorRel.* SELECT debitorRel.*
FROM hs_office.relation debitorRel FROM hs_office.relation debitorRel
JOIN hs_office.debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid JOIN hs_office.debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid
WHERE debitor.uuid = NEW.debitorUuid WHERE debitor.uuid = NEW.debitorUuid
INTO newDebitorRel; INTO newDebitorRel;
assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorUuid = %s', NEW.debitorUuid); assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorUuid = %s or project', NEW.debitorUuid);
perform rbac.defineRoleWithGrants( perform rbac.defineRoleWithGrants(

View File

@ -39,6 +39,8 @@ public abstract class ScenarioTest extends ContextBasedTest {
@Getter @Getter
private PrintWriter markdownFile; private PrintWriter markdownFile;
private StringBuilder debugLog = new StringBuilder();
record Alias<T extends UseCase<T>>(Class<T> useCase, UUID uuid) {} record Alias<T extends UseCase<T>>(Class<T> useCase, UUID uuid) {}
private final static Map<String, Alias<?>> aliases = new HashMap<>(); private final static Map<String, Alias<?>> aliases = new HashMap<>();
@ -57,22 +59,37 @@ public abstract class ScenarioTest extends ContextBasedTest {
@BeforeEach @BeforeEach
void init(final TestInfo testInfo) { void init(final TestInfo testInfo) {
createHostsharingPerson(); createHostsharingPerson();
try {
testInfo.getTestMethod().ifPresent(this::callRequiredProducers); testInfo.getTestMethod().ifPresent(this::callRequiredProducers);
createTestLogMarkdownFile(testInfo); createTestLogMarkdownFile(testInfo);
} catch (Exception exc) {
throw exc;
}
} }
@AfterEach @AfterEach
void cleanup() { void cleanup() {
properties.clear(); properties.clear();
if (markdownFile != null) {
markdownFile.close(); markdownFile.close();
} else {
toString();
}
debugLog = new StringBuilder();
} }
@SneakyThrows @SneakyThrows
void print(final String output) { void print(final String output) {
final var outputWithCommentsForUuids = UUIDAppender.appendUUIDKey(aliases, output.replace("+", "\\+"));
// for tests executed due to @Requires/@Produces there is no markdownFile yet // for tests executed due to @Requires/@Produces there is no markdownFile yet
if (markdownFile != null) { if (markdownFile != null) {
markdownFile.print(output); markdownFile.print(outputWithCommentsForUuids);
} }
// but the debugLog should contain all output
debugLog.append(outputWithCommentsForUuids);
} }
void printLine(final String output) { void printLine(final String output) {

View File

@ -0,0 +1,34 @@
package net.hostsharing.hsadminng.hs.office.scenarios;
import java.util.Map;
public class UUIDAppender {
public static String appendUUIDKey(Map<String, ScenarioTest.Alias<?>> uuidMap, String multilineText) {
// Split the multiline text into lines
String[] lines = multilineText.split("\\r?\\n");
// StringBuilder to build the resulting multiline text
StringBuilder result = new StringBuilder();
// Iterate over each line
for (String line : lines) {
// Iterate over the map to find if the line contains a UUID
for (Map.Entry<String, ScenarioTest.Alias<?>> entry : uuidMap.entrySet()) {
String uuidString = entry.getValue().uuid().toString();
// If the line contains the UUID, append the key at the end
if (line.contains(uuidString)) {
line = line + " // " + entry.getKey();
break; // Exit once we've matched one UUID
}
}
// Append the (possibly modified) line to the result
result.append(line).append("\n");
}
// Return the final modified text
return result.toString();
}
}

View File

@ -1,5 +1,6 @@
package net.hostsharing.hsadminng.hs.office.scenarios; package net.hostsharing.hsadminng.hs.office.scenarios;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
@ -17,10 +18,10 @@ import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers; import java.net.http.HttpResponse.BodyHandlers;
import java.time.Duration; import java.time.Duration;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
@ -67,7 +68,11 @@ public abstract class UseCase<T extends UseCase<?>> {
|------|-------|"""); |------|-------|""");
givenProperties.forEach((key, value) -> printLine("| " + key + " | " + value.toString().replace("\n", "<br>") + " |")); givenProperties.forEach((key, value) -> printLine("| " + key + " | " + value.toString().replace("\n", "<br>") + " |"));
printLine(""); printLine("");
requirements.forEach((alias, factory) -> factory.apply(alias).run().keep()); requirements.forEach((alias, factory) -> {
if (!ScenarioTest.containsAlias(alias)) {
factory.apply(alias).run().keep();
}
});
return run(); return run();
} }
protected abstract HttpResponse run(); protected abstract HttpResponse run();
@ -144,7 +149,7 @@ public abstract class UseCase<T extends UseCase<?>> {
.timeout(Duration.ofSeconds(10)) .timeout(Duration.ofSeconds(10))
.build(); .build();
final var response = client.send(request, BodyHandlers.ofString()); final var response = client.send(request, BodyHandlers.ofString());
return new HttpResponse(HttpMethod.PATCH, uriPath, null, response); return new HttpResponse(HttpMethod.DELETE, uriPath, null, response);
} }
public final UUID uuid(final String alias) { public final UUID uuid(final String alias) {
@ -240,8 +245,20 @@ public abstract class UseCase<T extends UseCase<?>> {
new ScenarioTest.Alias<>(UseCase.this.getClass(), locationUuid)); new ScenarioTest.Alias<>(UseCase.this.getClass(), locationUuid));
} }
@SneakyThrows
public HttpResponse expectArrayElements(final int expectedElementCount) {
final var rootNode = objectMapper.readTree(response.body());
assertThat(rootNode.isArray()).as("array expected, but got: " + response.body()).isTrue();
final var root = (List<?>) objectMapper.readValue(response.body(), new TypeReference<List<Object>>() {
});
assertThat(root.size()).as("unexpected number of array elements").isEqualTo(expectedElementCount);
return this;
}
@SneakyThrows @SneakyThrows
public String getFromBody(final String path) { public String getFromBody(final String path) {
// FIXME: use JsonPath: https://www.baeldung.com/guide-to-jayway-jsonpath
final var rootNode = objectMapper.readTree(response.body()); final var rootNode = objectMapper.readTree(response.body());
return getPropertyFromJson(rootNode, path); return getPropertyFromJson(rootNode, path);
} }

View File

@ -16,9 +16,9 @@ public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPar
@Override @Override
protected HttpResponse run() { protected HttpResponse run() {
keep("partnerPersonUuid", () -> keep("partnerPersonUuid", () ->
httpGet("/api/hs/office/relations?personData=" + uriEncoded("%{partnerPersonTradeName}")) httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerPersonTradeName}"))
.expecting(OK).expecting(JSON), .expecting(OK).expecting(JSON),
response -> response.getFromBody("[0].holder.uuid") response -> response.expectArrayElements(1).getFromBody("[0].holder.uuid")
); );
printPara("From that output above, we're taking the UUID of the holder of the first result element."); printPara("From that output above, we're taking the UUID of the holder of the first result element.");
printPara("**HINT**: With production data, you might get multiple results and have to decide which is the right one."); printPara("**HINT**: With production data, you might get multiple results and have to decide which is the right one.");
@ -49,7 +49,7 @@ public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPar
return httpPost("/api/hs/office/debitors", usingJsonBody(""" return httpPost("/api/hs/office/debitors", usingJsonBody("""
{ {
"debitorRel": { "debitorRel": {
"type": "DEBITOR", // FIXME: should be defaulted to DEBITOR "type": "DEBITOR", // TODO.impl: should become defaulted to DEBITOR
"anchorUuid": ${partnerPersonUuid}, "anchorUuid": ${partnerPersonUuid},
"holderUuid": ${partnerPersonUuid}, "holderUuid": ${partnerPersonUuid},
"contactUuid": ${Contact: Test AG - billing department} "contactUuid": ${Contact: Test AG - billing department}

View File

@ -10,7 +10,7 @@ public class DeleteDebitor extends UseCase<DeleteDebitor> {
super(testSuite); super(testSuite);
requires("Debitor: Test AG - delete debitor", alias -> new CreateSelfDebitorForPartner(testSuite, alias) requires("Debitor: Test AG - delete debitor", alias -> new CreateSelfDebitorForPartner(testSuite, alias)
.given("partnerPersonUuid", "%{Person: Test AG}") .given("partnerPersonTradeName", "Test AG")
.given("billingContactCaption", "Test AG - billing department") .given("billingContactCaption", "Test AG - billing department")
.given("billingContactEmailAddress", "billing@test-ag.example.org") .given("billingContactEmailAddress", "billing@test-ag.example.org")
.given("debitorNumberSuffix", "%{debitorSuffix}") .given("debitorNumberSuffix", "%{debitorSuffix}")