diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/HsOfficeUseCasesTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/HsOfficeUseCasesTest.java index 2d218400..04f32f35 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/HsOfficeUseCasesTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/HsOfficeUseCasesTest.java @@ -25,16 +25,14 @@ class HsOfficeUseCasesTest extends UseCaseTest { @Test @Order(1010) void shouldCreatePartner() { - keep("partner:Test AG.uuid", () -> - new CreatePartner(this) - .given("partnerNumber", 30001) - .given("personType", "LEGAL_PERSON") - .given("tradeName", "Test AG") - .given("contactCaption", "Test AG - Bord of Directors") - .given("emailAddress", "bord-of-directors@test-ag.example.org") - .doRun() - .keepingAs() - ); + new CreatePartner(this, "Partner: Test AG") + .given("partnerNumber", 30001) + .given("personType", "LEGAL_PERSON") + .given("tradeName", "Test AG") + .given("contactCaption", "Test AG - Bord of Directors") + .given("emailAddress", "bord-of-directors@test-ag.example.org") + .doRun() + .keep(); } @Test @@ -48,7 +46,9 @@ class HsOfficeUseCasesTest extends UseCaseTest { @Test @Order(2000) void shouldCreateSelfDebitorForPartner() { - new CreateSelfDebitorForPartner(this).doRun(); + new CreateSelfDebitorForPartner(this, "Debitor: Test AG - main debitor") + .doRun() + .keep(); } @Test diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/UseCase.java b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/UseCase.java index 03543e30..da1b03b0 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/UseCase.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/UseCase.java @@ -16,8 +16,11 @@ import java.util.ArrayList; import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import java.util.function.Supplier; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.nio.file.StandardOpenOption.APPEND; import static java.nio.file.StandardOpenOption.CREATE; @@ -29,19 +32,26 @@ import static org.hamcrest.Matchers.startsWith; public abstract class UseCase> { private final UseCaseTest testSuite; - private final Map>> requirements = new LinkedMap<>(); + private final Map>> requirements = new LinkedMap<>(); + private final String resultAlias; private String nextTitle; public UseCase(final UseCaseTest testSuite) { - this.testSuite = testSuite; - log(); - log("## Testcase " + this.getClass().getSimpleName().replaceAll("([a-z])([A-Z]+)", "$1 $2")); - log(""); + this(testSuite, null); } - public final void requires(final String alias, final Supplier> useCaseSupplier) { + public UseCase(final UseCaseTest testSuite, final String resultAlias) { + this.testSuite = testSuite; + this.resultAlias = resultAlias; + if (resultAlias != null) { + log("### UseCase " + resultAlias); + log(""); + } + } + + public final void requires(final String alias, final Function> useCaseFactory) { if ( !UseCaseTest.aliases.containsKey(alias) ) { - requirements.put(alias, useCaseSupplier); + requirements.put(alias, useCaseFactory); } } @@ -53,7 +63,7 @@ public abstract class UseCase> { } public final HttpResponse doRun() { - requirements.forEach((alias, supplier) -> supplier.get().run().keepingAs(alias)); + requirements.forEach((alias, factpory) -> factpory.apply(alias).run()); return run(); } @@ -70,7 +80,7 @@ public abstract class UseCase> { public final void keep(final String alias, final Supplier http) { this.nextTitle = alias; // FIXME: ugly - http.get().keepingAs(alias); + http.get().keep(); this.nextTitle = null; } @@ -108,10 +118,7 @@ public abstract class UseCase> { String resolvePlaceholders() { var partiallyResolved = new AtomicReference<>(template); - Streams.concat( - UseCaseTest.aliases.entrySet().stream().map(e -> Map.entry(e.getKey(), e.getValue().uuid())), - UseCaseTest.properties.entrySet().stream() - ).forEach(entry -> partiallyResolved.set( + UseCaseTest.knowVariables().forEach(entry -> partiallyResolved.set( partiallyResolved.get().replace("${" + entry.getKey() + "}", optionallyQuoted(entry.getValue()))) ); verifyAllPlaceholdersResolved(partiallyResolved.get()); @@ -135,7 +142,12 @@ public abstract class UseCase> { unresolvedPlaceholders.add(matcher.group()); } - assertThat(unresolvedPlaceholders).as("unresolved placeholders").hasSize(0); + final var knownVariables = UseCaseTest.knowVariables() + .map(e -> '"' + e.getKey() + "\": \"" + e.getValue() + '"') + .collect(Collectors.joining("\n ")); + assertThat(unresolvedPlaceholders) + .as("known variables: [\n " + knownVariables + "\n]\nunresolved placeholders:") + .isEmpty(); } } @@ -162,10 +174,12 @@ public abstract class UseCase> { if (nextTitle != null) { log("\n### " + nextTitle + "\n"); + } else if (resultAlias != null) { + log("\n### " + resultAlias + "\n"); } log("```"); log(httpMethod.name() + " " + uri); - log(requestBody + "=> status : " + status + " " + + log(requestBody + "=> status: " + status + " " + (locationUuid != null ? locationUuid : "")); log("```"); log(""); @@ -181,19 +195,15 @@ public abstract class UseCase> { return this; } - public void keepingAs(final String uuidAliasName) { - UseCaseTest.aliases.put(uuidAliasName, new UseCaseTest.Alias(self().getClass(), locationUuid)); + public void keep() { + UseCaseTest.aliases.put( + nextTitle != null ? nextTitle : resultAlias, + new UseCaseTest.Alias<>(UseCase.this.getClass(), locationUuid)); } } - @SneakyThrows - void log() { - Files.write(Paths.get(getClass().getSimpleName() + ".md"), "".getBytes(), CREATE, TRUNCATE_EXISTING); - } - - @SneakyThrows void log(final String output) { - Files.write(Paths.get(getClass().getSimpleName() + ".md"), (output+"\n").getBytes(), APPEND); + testSuite.log(output); } protected T self() { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/UseCaseTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/UseCaseTest.java index bed5318a..d8819db0 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/UseCaseTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/UseCaseTest.java @@ -1,5 +1,8 @@ package net.hostsharing.hsadminng.hs.office.usecases; +import com.tngtech.archunit.thirdparty.com.google.common.collect.Streams; +import lombok.Getter; +import lombok.SneakyThrows; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRepository; import net.hostsharing.hsadminng.lambda.Reducer; @@ -7,19 +10,28 @@ import net.hostsharing.hsadminng.rbac.context.ContextBasedTest; import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.server.LocalServerPort; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.UUID; - -import static org.assertj.core.api.Assumptions.assumeThat; +import java.util.stream.Stream; public abstract class UseCaseTest extends ContextBasedTest { final static String RUN_AS_USER = "superuser-alex@hostsharing.net"; // TODO.test: use global:AGENT when implemented + @Getter + public static TestInfo currentTestInfo; + + @Getter + private PrintWriter markdownFile; + record Alias>(Class useCase, UUID uuid) {} final static Map> aliases = new HashMap<>(); @@ -34,13 +46,14 @@ public abstract class UseCaseTest extends ContextBasedTest { @Autowired JpaAttempt jpaAttempt; + @SneakyThrows @BeforeEach - void init() { + void init(final TestInfo testInfo) { jpaAttempt.transacted(() -> { context.define("superuser-alex@hostsharing.net"); aliases.put( - "person:Hostsharing eG.uuid", + "Person: Hostsharing eG", new Alias<>( null, personRepo.findPersonByOptionalNameLike("Hostsharing eG") @@ -50,10 +63,28 @@ public abstract class UseCaseTest extends ContextBasedTest { ); } ); + + final var testMethodName = testInfo.getTestMethod().map(Method::getName).orElseThrow(); + markdownFile = new PrintWriter(new FileWriter(testMethodName + ".md")); + log("## Testcase " + testMethodName.replaceAll("([a-z])([A-Z]+)", "$1 $2")); + currentTestInfo = testInfo; // FIXME: remove? } @AfterEach void cleanup() { properties.clear(); + markdownFile.close(); + } + + @SneakyThrows + void log(final String output) { + markdownFile.println(output); + } + + static Stream> knowVariables() { + return Streams.concat( + UseCaseTest.aliases.entrySet().stream().map(e -> Map.entry(e.getKey(), e.getValue().uuid())), + UseCaseTest.properties.entrySet().stream() + ); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/debitor/CreateSelfDebitorForPartner.java b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/debitor/CreateSelfDebitorForPartner.java index 64856ca5..8f310ea0 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/debitor/CreateSelfDebitorForPartner.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/debitor/CreateSelfDebitorForPartner.java @@ -8,15 +8,15 @@ import static org.springframework.http.HttpStatus.CREATED; public class CreateSelfDebitorForPartner extends UseCase { - public CreateSelfDebitorForPartner(final UseCaseTest testSuite) { - super(testSuite); + public CreateSelfDebitorForPartner(final UseCaseTest testSuite, final String resultAlias) { + super(testSuite, resultAlias); - requires("person:Test AG.uuid"); + requires("Person: Test AG"); } @Override protected HttpResponse run() { - keep("bankaccount:Test AG - refund bank account.uuid", () -> + keep("BankAccount: Test AG - refund bank account", () -> httpPost("/api/hs/office/bankaccounts", usingJsonBody(""" { "holder": "Test AG - refund bank account", @@ -27,7 +27,7 @@ public class CreateSelfDebitorForPartner extends UseCase + keep("Contact: Test AG - billing department", () -> httpPost("/api/hs/office/contacts", usingJsonBody(""" { "caption": "Test AG - billing department", @@ -39,14 +39,13 @@ public class CreateSelfDebitorForPartner extends UseCase - httpPost("/api/hs/office/debitors", usingJsonBody(""" + return httpPost("/api/hs/office/debitors", usingJsonBody(""" { "debitorRel": { "type": "DEBITOR", // FIXME: should be defaulted to DEBITOR "anchorUuid": ${person:Test AG.uuid}, "holderUuid": ${person:Test AG.uuid}, - "contactUuid": ${contact:Test AG - billing department.uuid} + "contactUuid": ${Contact: Test AG - billing department} }, "debitorNumberSuffix": "00", "billable": true, @@ -54,12 +53,10 @@ public class CreateSelfDebitorForPartner extends UseCase { public CreateMembership(final UseCaseTest testSuite) { super(testSuite); - requires("partner:Test AG.uuid"); + requires("partner: Test AG.uuid"); } @Override protected HttpResponse run() { - httpPost("/api/hs/office/memberships", usingJsonBody(""" - { - "partnerUuid": "${partner:Test AG.uuid}", - "memberNumberSuffix": "00", - "validFrom": "2024-10-15", - "membershipFeeBillable": "true" - } - """)) - .expecting(HttpStatus.CREATED).expecting(ContentType.JSON) - .keepingAs("membership:Test AG 00.uuid"); + keep("membership:Test AG 00.uuid", () -> + httpPost("/api/hs/office/memberships", usingJsonBody(""" + { + "partnerUuid": "${partner:Test AG.uuid}", + "memberNumberSuffix": "00", + "validFrom": "2024-10-15", + "membershipFeeBillable": "true" + } + """)) + .expecting(HttpStatus.CREATED).expecting(ContentType.JSON) + ); return null; } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/partner/CreatePartner.java b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/partner/CreatePartner.java index 15c8f909..0c6d7298 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/partner/CreatePartner.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/partner/CreatePartner.java @@ -8,13 +8,17 @@ import org.springframework.http.HttpStatus; public class CreatePartner extends UseCase { public CreatePartner(final UseCaseTest testSuite) { - super(testSuite); + super(testSuite, null); + } + + public CreatePartner(final UseCaseTest testSuite, final String resultAlias) { + super(testSuite, resultAlias); } @Override protected HttpResponse run() { - keep("person:Test AG.uuid", () -> + keep("Person: Test AG", () -> httpPost("/api/hs/office/persons", usingJsonBody(""" { "personType": ${personType}, @@ -24,7 +28,7 @@ public class CreatePartner extends UseCase { .expecting(HttpStatus.CREATED).expecting(ContentType.JSON) ); - keep("contact:Test AG - Bord of Directors.uuid", () -> + keep("Contact: Test AG - Bord of Directors", () -> httpPost("/api/hs/office/contacts", usingJsonBody(""" { "caption": ${contactCaption}, @@ -40,9 +44,9 @@ public class CreatePartner extends UseCase { { "partnerNumber": ${partnerNumber}, "partnerRel": { - "anchorUuid": ${person:Hostsharing eG.uuid}, - "holderUuid": ${person:Test AG.uuid}, - "contactUuid": ${contact:Test AG - Bord of Directors.uuid} + "anchorUuid": ${Person: Hostsharing eG}, + "holderUuid": ${Person: Test AG}, + "contactUuid": ${Contact: Test AG - Bord of Directors} }, "details": { "registrationOffice": "Registergericht Hamburg", diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/partner/DeletePartner.java b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/partner/DeletePartner.java index c5bb9d2a..6e50b7fe 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/partner/DeletePartner.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/usecases/partner/DeletePartner.java @@ -9,7 +9,7 @@ public class DeletePartner extends UseCase { public DeletePartner(final UseCaseTest testSuite) { super(testSuite); - requires("partner:Delete AG:uuid", () -> new CreatePartner(testSuite) + requires("Partner: Delete AG", alias -> new CreatePartner(testSuite, alias) .given("personType", "LEGAL_PERSON") .given("tradeName", "Delete AG") .given("contactCaption", "Delete AG - Bord of Directors") @@ -18,7 +18,7 @@ public class DeletePartner extends UseCase { @Override protected HttpResponse run() { - httpDelete("/api/hs/office/partners/" + uuid("partner:Delete AG:uuid")) + httpDelete("/api/hs/office/partners/" + uuid("Partner: Delete AG")) .expecting(HttpStatus.NO_CONTENT); return null; }