find Person using HTTP GET in CreateSelfDebitorForPartner instead of using the UUID directly
This commit is contained in:
parent
87e8576ce7
commit
e12d0b0ba2
@ -112,7 +112,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
@Produces("Debitor: Test AG - main debitor")
|
||||
void shouldCreateSelfDebitorForPartner() {
|
||||
new CreateSelfDebitorForPartner(this, "Debitor: Test AG - main debitor")
|
||||
.given("partnerPersonUuid", "%{Person: Test AG}")
|
||||
.given("partnerPersonTradeName", "Test AG")
|
||||
.given("billingContactCaption", "Test AG - billing department")
|
||||
.given("billingContactEmailAddress", "billing@test-ag.example.org")
|
||||
.given("debitorNumberSuffix", "00") // TODO.impl: could be assigned automatically, but is not yet
|
||||
|
@ -179,12 +179,12 @@ public abstract class ScenarioTest extends ContextBasedTest {
|
||||
return map;
|
||||
}
|
||||
|
||||
static String resolve(final String text) {
|
||||
public static String resolve(final String text) {
|
||||
final var resolved = new TemplateResolver(text, ScenarioTest.knowVariables()).resolve();
|
||||
return resolved;
|
||||
}
|
||||
|
||||
static Object resolveTyped(final String text) {
|
||||
public static Object resolveTyped(final String text) {
|
||||
final var resolved = resolve(text);
|
||||
try {
|
||||
return UUID.fromString(resolved);
|
||||
|
@ -1,6 +1,9 @@
|
||||
package net.hostsharing.hsadminng.hs.office.scenarios;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.restassured.http.ContentType;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import net.hostsharing.hsadminng.reflection.AnnotationFinder;
|
||||
import org.apache.commons.collections4.map.LinkedMap;
|
||||
@ -14,6 +17,7 @@ import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpRequest.BodyPublishers;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import java.time.Duration;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -22,6 +26,7 @@ import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static java.net.URLEncoder.encode;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.platform.commons.util.StringUtils.isBlank;
|
||||
import static org.junit.platform.commons.util.StringUtils.isNotBlank;
|
||||
@ -29,8 +34,9 @@ import static org.junit.platform.commons.util.StringUtils.isNotBlank;
|
||||
public abstract class UseCase<T extends UseCase<?>> {
|
||||
|
||||
private static final HttpClient client = HttpClient.newHttpClient();
|
||||
final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private final ScenarioTest testSuite;
|
||||
protected final ScenarioTest testSuite;
|
||||
private final Map<String, Function<String, UseCase<?>>> requirements = new LinkedMap<>();
|
||||
private final String resultAlias;
|
||||
private final Map<String, Object> givenProperties = new LinkedHashMap<>();
|
||||
@ -76,17 +82,35 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
return new JsonTemplate(jsonTemplate);
|
||||
}
|
||||
|
||||
public final void keep(final String alias, final Supplier<HttpResponse> http, final Function<HttpResponse, String> extractor) {
|
||||
this.nextTitle = ScenarioTest.resolve(alias);
|
||||
http.get().keep(extractor);
|
||||
this.nextTitle = null;
|
||||
}
|
||||
|
||||
public final void keep(final String alias, final Supplier<HttpResponse> http) {
|
||||
this.nextTitle = ScenarioTest.resolve(alias);
|
||||
http.get().keep();
|
||||
this.nextTitle = null;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpGet(final String uriPath) {
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.GET()
|
||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||
.header("current-subject", ScenarioTest.RUN_AS_USER)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
final var response = client.send(request, BodyHandlers.ofString());
|
||||
return new HttpResponse(HttpMethod.POST, uriPath, null, response);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpPost(final String uriPath, final JsonTemplate bodyJsonTemplate) {
|
||||
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.method(HttpMethod.POST.toString(), BodyPublishers.ofString(requestBody))
|
||||
.POST(BodyPublishers.ofString(requestBody))
|
||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||
.header("Content-Type", "application/json")
|
||||
.header("current-subject", ScenarioTest.RUN_AS_USER)
|
||||
@ -127,6 +151,10 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
return ScenarioTest.uuid(alias);
|
||||
}
|
||||
|
||||
public String uriEncoded(final String text) {
|
||||
return encode(ScenarioTest.resolve(text));
|
||||
}
|
||||
|
||||
public static class JsonTemplate {
|
||||
|
||||
private final String template;
|
||||
@ -142,8 +170,12 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
|
||||
public class HttpResponse {
|
||||
|
||||
@Getter
|
||||
private final java.net.http.HttpResponse<String> response;
|
||||
|
||||
@Getter
|
||||
private final HttpStatus status;
|
||||
|
||||
private UUID locationUuid;
|
||||
|
||||
public HttpResponse(
|
||||
@ -187,6 +219,16 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void keep(final Function<HttpResponse, String> extractor) {
|
||||
final var alias = nextTitle != null ? nextTitle : resultAlias;
|
||||
assertThat(alias).as("cannot keep result, no alias found").isNotNull();
|
||||
|
||||
final var value = extractor.apply(this);
|
||||
ScenarioTest.putAlias(
|
||||
alias,
|
||||
new ScenarioTest.Alias<>(UseCase.this.getClass(), UUID.fromString(value)));
|
||||
}
|
||||
|
||||
public void keep() {
|
||||
final var alias = nextTitle != null ? nextTitle : resultAlias;
|
||||
assertThat(alias).as("cannot keep result, no alias found").isNotNull();
|
||||
@ -194,6 +236,12 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
alias,
|
||||
new ScenarioTest.Alias<>(UseCase.this.getClass(), locationUuid));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String getFromBody(final String path) {
|
||||
final var rootNode = objectMapper.readTree(response.body());
|
||||
return getPropertyFromJson(rootNode, path);
|
||||
}
|
||||
}
|
||||
|
||||
public void print(final String output) {
|
||||
@ -231,4 +279,55 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
private final String title(String resultAlias) {
|
||||
return getClass().getSimpleName().replaceAll("([a-z])([A-Z]+)", "$1 $2") + " => " + resultAlias;
|
||||
}
|
||||
|
||||
// FIXME: refactor to own class
|
||||
/**
|
||||
* Extracts a property from a JsonNode based on a dotted path.
|
||||
* Supports array notation like "users[0].address.city" and root arrays like "[0].user.address.city".
|
||||
*
|
||||
* @param rootNode the root JsonNode
|
||||
* @param propertyPath the property path in dot notation (e.g., "[0].user.address.city")
|
||||
* @return the extracted property value as a String
|
||||
*/
|
||||
public static String getPropertyFromJson(final JsonNode rootNode, final String propertyPath) {
|
||||
final var pathParts = propertyPath.split("\\.");
|
||||
var currentNode = rootNode;
|
||||
|
||||
// Traverse the JSON structure based on the path parts
|
||||
for (final var part : pathParts) {
|
||||
// Check if the part contains array notation like "[0]"
|
||||
if (part.contains("[")) {
|
||||
String arrayName;
|
||||
final var arrayIndex = Integer.parseInt(part.substring(part.indexOf("[") + 1, part.indexOf("]")));
|
||||
|
||||
if (part.startsWith("[")) {
|
||||
// This is a root-level array access (e.g., "[0]")
|
||||
arrayName = null;
|
||||
} else {
|
||||
// This is a nested array access (e.g., "users[0]")
|
||||
arrayName = part.substring(0, part.indexOf("["));
|
||||
}
|
||||
|
||||
// If there's an array name, traverse to it
|
||||
if (arrayName != null) {
|
||||
currentNode = currentNode.path(arrayName);
|
||||
}
|
||||
|
||||
// Ensure the current node is an array, then access the element at the index
|
||||
if (currentNode.isArray()) {
|
||||
currentNode = currentNode.get(arrayIndex);
|
||||
}
|
||||
} else {
|
||||
// Traverse as a normal field
|
||||
currentNode = currentNode.path(part);
|
||||
}
|
||||
|
||||
// If at any point, the node is missing, return null
|
||||
if (currentNode.isMissingNode()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return currentNode.asText(); // Return the final value as a String
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPartner> {
|
||||
|
||||
@ -14,6 +15,12 @@ public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPar
|
||||
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
keep("partnerPersonUuid", () ->
|
||||
httpGet("/api/hs/office/relations?personData=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.getFromBody("[0].holder.uuid")
|
||||
);
|
||||
|
||||
keep("BankAccount: Test AG - refund bank account", () ->
|
||||
httpPost("/api/hs/office/bankaccounts", usingJsonBody("""
|
||||
{
|
||||
@ -57,4 +64,5 @@ public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPar
|
||||
"""))
|
||||
.expecting(CREATED).expecting(JSON);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user