Compare commits

..

No commits in common. "a1e04508ed480d3b5ea18b42857b53ab38333dfa" and "2b21c742f03906046b8e08f39f523920448d8cf1" have entirely different histories.

12 changed files with 244 additions and 542 deletions

View File

@ -0,0 +1,51 @@
package net.hostsharing.hsadminng.hs.office.usecases;
import io.restassured.http.ContentType;
import org.springframework.http.HttpStatus;
class HsOfficeCreatePartnerUseCase extends UseCase {
public HsOfficeCreatePartnerUseCase(final UseCaseTest testSuite) {
super(testSuite);
}
@Override
HttpResponse run() {
httpPost("/api/hs/office/persons", usingJsonBody("""
{
"personType": "LEGAL_PERSON",
"tradeName": "Test AG"
}
"""))
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
.keepingAs("person:Test AG.uuid");
httpPost("/api/hs/office/contacts", usingJsonBody("""
{
"caption": "Test AG - Bord of Directors",
"emailAddresses": {
"main": "bord-of-directors@test-ag.example.org"
}
}
"""))
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
.keepingAs("contact:Test AG - Bord of Directors.uuid");
return httpPost("/api/hs/office/partners", usingJsonBody("""
{
"partnerNumber": "30003",
"partnerRel": {
"anchorUuid": "${person:Hostsharing eG.uuid}",
"holderUuid": "${person:Test AG.uuid}",
"contactUuid": "${contact:Test AG - Bord of Directors.uuid}"
},
"details": {
"registrationOffice": "Registergericht Hamburg",
"registrationNumber": "1234567"
}
}
"""))
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON);
}
}

View File

@ -0,0 +1,59 @@
package net.hostsharing.hsadminng.hs.office.usecases;
import static io.restassured.http.ContentType.JSON;
import static org.springframework.http.HttpStatus.CREATED;
class HsOfficeDebitorUseCase extends UseCase {
public HsOfficeDebitorUseCase(final UseCaseTest testSuite) {
super(testSuite);
requires("person:Test AG.uuid", () -> new HsOfficeCreatePartnerUseCase(testSuite));
}
@Override
HttpResponse run() {
httpPost("/api/hs/office/bankaccounts", usingJsonBody("""
{
"holder": "Test AG - refund bank account",
"iban": "DE88100900001234567892",
"bic": "BEVODEBB"
}
"""))
.expecting(CREATED).expecting(JSON)
.keepingAs("bankaccount:Test AG - refund bank account.uuid");
httpPost("/api/hs/office/contacts", usingJsonBody("""
{
"caption": "Test AG - billing department",
"emailAddresses": {
"main": "billing@test-ag.example.org"
}
}
"""))
.expecting(CREATED).expecting(JSON)
.keepingAs("contact:Test AG - billing department.uuid");
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}"
},
"debitorNumberSuffix": "00",
"billable": "true",
"vatId": "VAT123456",
"vatCountryCode": "DE",
"vatBusiness": true,
"vatReverseCharge": "false",
"refundBankAccountUuid": "${bankaccount:Test AG - refund bank account.uuid}",
"defaultPrefix": "tst"
}
"""))
.expecting(CREATED).expecting(JSON)
.keepingAs("debitor:Test AG - Hauptdebitor.uuid");
return null;
}
}

View File

@ -0,0 +1,19 @@
package net.hostsharing.hsadminng.hs.office.usecases;
import org.springframework.http.HttpStatus;
class HsOfficeDeletePartnerUseCase extends UseCase {
public HsOfficeDeletePartnerUseCase(final UseCaseTest testSuite) {
super(testSuite);
requires("partner:Test AG for deletetion:uuid", () -> new HsOfficeCreatePartnerUseCase(testSuite));
}
@Override
HttpResponse run() {
httpDelete("/api/hs/office/partners/" + uuid("partner:Test AG.uuid"))
.expecting(HttpStatus.NO_CONTENT);
return null;
}
}

View File

@ -0,0 +1,26 @@
package net.hostsharing.hsadminng.hs.office.usecases;
import io.restassured.http.ContentType;
import org.springframework.http.HttpStatus;
class HsOfficeMembershipUseCase extends UseCase {
public HsOfficeMembershipUseCase(final UseCaseTest testSuite) {
super(testSuite);
}
@Override
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");
return null;
}
}

View File

@ -1,16 +1,13 @@
package net.hostsharing.hsadminng.hs.office.usecases; package net.hostsharing.hsadminng.hs.office.usecases;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.hs.office.usecases.debitor.CreateSelfDebitorForPartner;
import net.hostsharing.hsadminng.hs.office.usecases.membership.CreateMembership;
import net.hostsharing.hsadminng.hs.office.usecases.partner.CreatePartner;
import net.hostsharing.hsadminng.hs.office.usecases.partner.DeletePartner;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest( @SpringBootTest(
@ -19,50 +16,31 @@ import org.springframework.boot.test.context.SpringBootTest;
) )
@Tag("useCaseTest") @Tag("useCaseTest")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ExtendWith(OrderedDependedTestsExtension.class)
class HsOfficeUseCasesTest extends UseCaseTest { class HsOfficeUseCasesTest extends UseCaseTest {
@Test @Test
@Order(1010) @Order(1010)
void shouldCreatePartner() { void shouldCreatePartner() {
new CreatePartner(this, "Partner: Test AG") new HsOfficeCreatePartnerUseCase(this).run()
.given("partnerNumber", 30001) .keepingAs("partner:Test AG.uuid");
.given("personType", "LEGAL_PERSON") }
.given("tradeName", "Test AG")
.given("contactCaption", "Test AG - Bord of Directors") @Test
.given("emailAddress", "bord-of-directors@test-ag.example.org") @Order(1011)
.doRun() void shouldDeletePartner() {
.keep(); new HsOfficeDeletePartnerUseCase(this).run();
} }
@Test @Test
@Order(1020) @Order(1020)
void shouldDeletePartner() {
new DeletePartner(this)
.given("partnerNumber", 31020)
.doRun();
}
@Test
@Order(2000)
void shouldCreateSelfDebitorForPartner() { void shouldCreateSelfDebitorForPartner() {
new CreateSelfDebitorForPartner(this, "Debitor: Test AG - main debitor") new HsOfficeDebitorUseCase(this).run();
.given("partnerPersonUuid", "%{Person: 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
.given("billable", true)
.given("vatId", "VAT123456")
.given("vatCountryCode", "DE")
.given("vatBusiness", true)
.given("vatReverseCharge", false)
.given("defaultPrefix", "tst")
.doRun()
.keep();
} }
@Test @Test
@Order(3000) @Order(1030)
void shouldCreateMembershipForPartner() { void shouldCreateMembershipForPartner() {
new CreateMembership(this).doRun(); new HsOfficeMembershipUseCase(this).run();
} }
} }

View File

@ -1,138 +0,0 @@
package net.hostsharing.hsadminng.hs.office.usecases;
import java.util.Map;
public class TemplateResolver {
private final String template;
private final Map<String, Object> properties;
private final StringBuilder resolved = new StringBuilder();
private int position = 0;
public TemplateResolver(final String template, final Map<String, Object> properties) {
this.template = template;
this.properties = properties;
}
String resolve() {
copy();
return resolved.toString();
}
private void copy() {
while (hasMoreChars()) {
if ((currentChar() == '$' || currentChar() == '%') && nextChar() == '{') {
startPlaceholder(currentChar());
} else {
resolved.append(fetchChar());
}
}
}
private boolean hasMoreChars() {
return position < template.length();
}
private void startPlaceholder(final char intro) {
skipChars(intro + "{");
int nested = 0;
final var placeholder = new StringBuilder();
while (nested > 0 || currentChar() != '}') {
if (currentChar() == '}') {
--nested;
placeholder.append(fetchChar());
} else if ((currentChar() == '$' || currentChar() == '%') && nextChar() == '{') {
++nested;
placeholder.append(fetchChar());
} else {
placeholder.append(fetchChar());
}
}
final var name = new TemplateResolver(placeholder.toString(), properties).resolve();
final var value = propVal(name);
if ( intro == '%') {
resolved.append(value);
} else {
resolved.append(optionallyQuoted(value));
}
skipChar('}');
}
private Object propVal(final String name) {
final var val = properties.get(name);
if (val == null) {
throw new IllegalStateException("Missing required property: " + name);
}
return val;
}
private void skipChar(final char expectedChar) {
if (currentChar() != expectedChar) {
throw new IllegalStateException("expected '" + expectedChar + "' but got '" + currentChar() + "'");
}
++position;
}
private void skipChars(final String expectedChars) {
final var nextChars = template.substring(position, position + expectedChars.length());
if ( !nextChars.equals(expectedChars) ) {
throw new IllegalStateException("expected '" + expectedChars + "' but got '" + nextChars + "'");
}
position += expectedChars.length();
}
private char fetchChar() {
if ((position+1) > template.length()) {
throw new IllegalStateException("no more characters. resolved so far: " + resolved);
}
final var currentChar = currentChar();
//System.out.println("fetched #" + position + ": " + currentChar);
++position;
return currentChar;
}
private char currentChar() {
if (position >= template.length()) {
throw new IllegalStateException("no more characters. resolved so far: " + resolved);
}
return template.charAt(position);
}
private char nextChar() {
if ((position+1) >= template.length()) {
throw new IllegalStateException("no more characters. resolved so far: " + resolved);
}
return template.charAt(position+1);
}
private static String optionallyQuoted(final Object value) {
return switch (value) {
case Boolean bool -> bool.toString();
case Number number -> number.toString();
default -> "\"" + value + "\"";
};
}
public static void main(String[] args) {
System.out.println(
new TemplateResolver("""
etwas davor,
${einfacher Platzhalter},
${verschachtelter %{Name}},
und nochmal ohne Quotes:
%{einfacher Platzhalter},
%{verschachtelter %{Name}},
etwas danach.
""",
Map.ofEntries(
Map.entry("Name", "placeholder"),
Map.entry("einfacher Platzhalter", "simple placeholder"),
Map.entry("verschachtelter placeholder", "nested placeholder")
)).resolve());
}
}

View File

@ -4,102 +4,58 @@ import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import io.restassured.response.Response; import io.restassured.response.Response;
import io.restassured.response.ValidatableResponse; import io.restassured.response.ValidatableResponse;
import org.apache.commons.collections4.map.LinkedMap;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Pattern;
import static org.assertj.core.api.Assumptions.assumeThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
public abstract class UseCase<T extends UseCase<?>> { public abstract class UseCase {
private final UseCaseTest testSuite; private final UseCaseTest testSuite;
private final Map<String, Function<String, UseCase<?>>> requirements = new LinkedMap<>();
private final String resultAlias;
private String nextTitle; // FIXME: ugly
public UseCase(final UseCaseTest testSuite) { public UseCase(final UseCaseTest testSuite) {
this(testSuite, null);
}
public UseCase(final UseCaseTest testSuite, final String resultAlias) {
this.testSuite = testSuite; this.testSuite = testSuite;
this.resultAlias = resultAlias; }
if (resultAlias != null) {
log("### UseCase " + resultAlias); void requires(final String alias, final Supplier<UseCase> useCaseSupplier) {
log(""); if ( !UseCaseTest.aliases.containsKey(alias) ) {
useCaseSupplier.get().run().keepingAs(alias);
} }
} }
public final void requires(final String alias, final Function<String, UseCase<?>> useCaseFactory) { abstract HttpResponse run();
if (!UseCaseTest.containsAlias(alias)) {
requirements.put(alias, useCaseFactory);
}
}
public void requires(final String alias) { JsonTemplate usingJsonBody(final String jsonTemplate) {
assumeThat(UseCaseTest.containsAlias(alias))
.as("skipping because alias '" + alias + "' not found, maybe the other test failed?")
.isTrue();
log("depends on [" + alias + "](" + UseCaseTest.getAlias(alias).useCase().getSimpleName() + ".md)");
}
public final HttpResponse doRun() {
log("### Given Properties\n");
log("""
| name | value |
|------|-------|
""".trim());
UseCaseTest.properties().forEach((key, value) -> log("| " + key + " | " + value + " |"));
log("");
requirements.forEach((alias, factory) -> factory.apply(alias).run().keep());
return run();
}
protected abstract HttpResponse run();
public final UseCase<T> given(final String propName, final Object propValue) {
UseCaseTest.putProperty(propName, propValue);
return this;
}
public final JsonTemplate usingJsonBody(final String jsonTemplate) {
return new JsonTemplate(jsonTemplate); return new JsonTemplate(jsonTemplate);
} }
public final void keep(final String alias, final Supplier<HttpResponse> http) { HttpResponse httpPost(final String uriPath, final JsonTemplate bodyJsonTemplate) {
this.nextTitle = UseCaseTest.resolve(alias);
http.get().keep();
this.nextTitle = null;
}
public final HttpResponse httpPost(final String uriPath, final JsonTemplate bodyJsonTemplate) {
final var body = bodyJsonTemplate.resolvePlaceholders();
final var uri = "http://localhost" + uriPath;
final var response = RestAssured.given() final var response = RestAssured.given()
.header("current-subject", UseCaseTest.RUN_AS_USER) .header("current-subject", UseCaseTest.RUN_AS_USER)
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(body) .body(bodyJsonTemplate.with(UseCaseTest.aliases))
.port(testSuite.port) .port(testSuite.port)
.when().post(uri); .when().post("http://localhost" + uriPath);
return new HttpResponse(HttpMethod.POST, uriPath, body, response); return new HttpResponse(response);
} }
public final HttpResponse httpDelete(final String uriPath) { HttpResponse httpDelete(final String uriPath) {
final var response = RestAssured.given() final var response = RestAssured.given()
.header("current-subject", UseCaseTest.RUN_AS_USER) .header("current-subject", UseCaseTest.RUN_AS_USER)
.port(testSuite.port) .port(testSuite.port)
.when().delete("http://localhost" + uriPath); .when().delete("http://localhost" + uriPath);
return new HttpResponse(HttpMethod.DELETE, uriPath, null, response); return new HttpResponse(response);
} }
public final UUID uuid(final String alias) { UUID uuid(final String alias) {
return UseCaseTest.getAlias(alias).uuid(); return testSuite.aliases.get(alias);
} }
static class JsonTemplate { static class JsonTemplate {
@ -110,71 +66,52 @@ public abstract class UseCase<T extends UseCase<?>> {
this.template = jsonTemplate; this.template = jsonTemplate;
} }
String resolvePlaceholders() { String with(final Map<String, UUID> aliases) {
return UseCaseTest.resolve(template); var partiallyResolved = new AtomicReference<>(template);
aliases.forEach((k, v) ->
partiallyResolved.set(partiallyResolved.get().replace("${" + k + "}", v.toString())));
verifyAllPlaceholdersResolved(partiallyResolved.get());
return partiallyResolved.get();
}
private void verifyAllPlaceholdersResolved(final String remainingTemplate) {
final var pattern = Pattern.compile("\\$\\{[^}]+\\}");
final var matcher = pattern.matcher(remainingTemplate);
final var unresolvedPlaceholders = new ArrayList<>();
while (matcher.find()) {
unresolvedPlaceholders.add(matcher.group());
}
assertThat(unresolvedPlaceholders).as("unresolved placeholders").hasSize(0);
} }
} }
public class HttpResponse { class HttpResponse {
private final ValidatableResponse response; private final ValidatableResponse response;
private final HttpStatus status;
private UUID locationUuid;
public HttpResponse( public HttpResponse(final Response response) {
final HttpMethod httpMethod, this.response = response.then().log().all().assertThat();
final String uri,
final String requestBody,
final Response response
) {
final var validatableResponse = response.then();
this.response = validatableResponse.log().all().assertThat();
this.status = HttpStatus.valueOf(response.statusCode());
if (response.statusCode() == HttpStatus.CREATED.value()) {
final var location = validatableResponse.header("Location", startsWith("http://localhost"))
.extract().header("Location");
locationUuid = UUID.fromString(location.substring(location.lastIndexOf('/') + 1));
} }
if (nextTitle != null) { HttpResponse expecting(final HttpStatus httpStatus) {
log("\n### " + nextTitle + "\n");
} else if (resultAlias != null) {
log("\n### " + resultAlias + "\n");
}
log("```");
log(httpMethod.name() + " " + uri);
log(requestBody + "=> status: " + status + " " +
(locationUuid != null ? locationUuid : ""));
if (!status.is2xxSuccessful()) {
log(response.getBody().prettyPrint());
}
log("```");
log("");
}
public HttpResponse expecting(final HttpStatus httpStatus) {
response.statusCode(httpStatus.value()); response.statusCode(httpStatus.value());
return this; return this;
} }
public HttpResponse expecting(final ContentType contentType) { HttpResponse expecting(final ContentType contentType) {
response.contentType(contentType); response.contentType(contentType);
return this; return this;
} }
public void keep() { void keepingAs(final String uuidAliasName) {
UseCaseTest.putAlias( final var location = response.header("Location", startsWith("http://localhost"))
nextTitle != null ? nextTitle : resultAlias, .extract().header("Location");
new UseCaseTest.Alias<>(UseCase.this.getClass(), locationUuid)); final var newSubjectUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
assertThat(newSubjectUuid).isNotNull();
UseCaseTest.aliases.put(uuidAliasName, newSubjectUuid);
} }
} }
void log(final String output) {
testSuite.log(output);
}
protected T self() {
//noinspection unchecked
return (T) this;
}
} }

View File

@ -1,43 +1,28 @@
package net.hostsharing.hsadminng.hs.office.usecases; package net.hostsharing.hsadminng.hs.office.usecases;
import lombok.Getter;
import lombok.SneakyThrows;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRepository;
import net.hostsharing.hsadminng.lambda.Reducer; import net.hostsharing.hsadminng.lambda.Reducer;
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest; import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestWatcher;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.web.server.LocalServerPort; 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.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assumptions.assumeThat;
public abstract class UseCaseTest extends ContextBasedTest { public abstract class UseCaseTest extends ContextBasedTest {
final static String RUN_AS_USER = "superuser-alex@hostsharing.net"; // TODO.test: use global:AGENT when implemented final static String RUN_AS_USER = "superuser-alex@hostsharing.net"; // TODO.test: use global:AGENT when implemented
@Getter final static Map<String, UUID> aliases = new HashMap<>();
public static TestInfo currentTestInfo;
@Getter
private PrintWriter markdownFile;
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, Object> properties = new HashMap<>();
@LocalServerPort @LocalServerPort
Integer port; Integer port;
@ -48,75 +33,33 @@ public abstract class UseCaseTest extends ContextBasedTest {
@Autowired @Autowired
JpaAttempt jpaAttempt; JpaAttempt jpaAttempt;
@SneakyThrows
@BeforeEach @BeforeEach
void init(final TestInfo testInfo) { void init() {
jpaAttempt.transacted(() -> jpaAttempt.transacted(() ->
{ {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
aliases.put( aliases.put(
"Person: Hostsharing eG", "person:Hostsharing eG.uuid",
new Alias<>(
null,
personRepo.findPersonByOptionalNameLike("Hostsharing eG") personRepo.findPersonByOptionalNameLike("Hostsharing eG")
.stream() .stream()
.map(HsOfficePersonEntity::getUuid) .map(HsOfficePersonEntity::getUuid)
.reduce(Reducer::toSingleElement).orElseThrow()) .reduce(Reducer::toSingleElement).orElseThrow());
);
} }
); );
}
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 class OrderedDependedTestsExtension implements TestWatcher, BeforeEachCallback {
void cleanup() {
properties.clear(); private static boolean previousTestsPassed = true;
markdownFile.close();
@Override
public void testFailed(final ExtensionContext context, final Throwable cause) {
previousTestsPassed = false;
} }
@SneakyThrows @Override
void log(final String output) { public void beforeEach(final ExtensionContext extensionContext) {
markdownFile.println(output); assumeThat(previousTestsPassed).isTrue();
} }
static boolean containsAlias(final String alias) {
return aliases.containsKey(alias);
}
static Alias<?> getAlias(final String name) {
final var alias = aliases.get(name);
assertThat(alias).as("alias '" + name + "' not found in aliases [" +
aliases.keySet().stream().map(v -> "'" + v + "'").collect(Collectors.joining(", ")) + "]"
).isNotNull();
return alias;
}
static void putAlias(final String name, final Alias<?> value) {
aliases.put(name, value);
}
static void putProperty(final String name, final Object value) {
properties.put(name, (value instanceof String string) ? resolve(string) : value);
}
static LinkedHashMap<String, Object> properties() {
return new LinkedHashMap<>(properties);
}
static Map<String, Object> knowVariables() {
final var map = new LinkedHashMap<String, Object>();
UseCaseTest.aliases.forEach((key, value) -> map.put(key, value.uuid()));
map.putAll(UseCaseTest.properties);
return map;
}
static String resolve(final String text) {
final var resolved = new TemplateResolver(text, UseCaseTest.knowVariables()).resolve();
return resolved;
}
} }

View File

@ -1,62 +0,0 @@
package net.hostsharing.hsadminng.hs.office.usecases.debitor;
import net.hostsharing.hsadminng.hs.office.usecases.UseCase;
import net.hostsharing.hsadminng.hs.office.usecases.UseCaseTest;
import static io.restassured.http.ContentType.JSON;
import static org.springframework.http.HttpStatus.CREATED;
public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPartner> {
public CreateSelfDebitorForPartner(final UseCaseTest testSuite, final String resultAlias) {
super(testSuite, resultAlias);
requires("Person: Test AG");
}
@Override
protected HttpResponse run() {
keep("BankAccount: Test AG - refund bank account", () ->
httpPost("/api/hs/office/bankaccounts", usingJsonBody("""
{
"holder": "Test AG - refund bank account",
"iban": "DE88100900001234567892",
"bic": "BEVODEBB"
}
"""))
.expecting(CREATED).expecting(JSON)
);
keep("Contact: Test AG - billing department", () ->
httpPost("/api/hs/office/contacts", usingJsonBody("""
{
"caption": ${billingContactCaption},
"emailAddresses": {
"main": ${billingContactEmailAddress}
}
}
"""))
.expecting(CREATED).expecting(JSON)
);
return httpPost("/api/hs/office/debitors", usingJsonBody("""
{
"debitorRel": {
"type": "DEBITOR", // FIXME: should be defaulted to DEBITOR
"anchorUuid": ${partnerPersonUuid},
"holderUuid": ${partnerPersonUuid},
"contactUuid": ${Contact: Test AG - billing department}
},
"debitorNumberSuffix": ${debitorNumberSuffix},
"billable": ${billable},
"vatId": ${vatId},
"vatCountryCode": ${vatCountryCode},
"vatBusiness": ${vatBusiness},
"vatReverseCharge": ${vatReverseCharge},
"refundBankAccountUuid": ${BankAccount: Test AG - refund bank account},
"defaultPrefix": ${defaultPrefix}
}
"""))
.expecting(CREATED).expecting(JSON);
}
}

View File

@ -1,31 +0,0 @@
package net.hostsharing.hsadminng.hs.office.usecases.membership;
import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.hs.office.usecases.UseCase;
import net.hostsharing.hsadminng.hs.office.usecases.UseCaseTest;
import org.springframework.http.HttpStatus;
public class CreateMembership extends UseCase<CreateMembership> {
public CreateMembership(final UseCaseTest testSuite) {
super(testSuite);
requires("Partner: Test AG");
}
@Override
protected HttpResponse run() {
keep("Membership: Test AG 00", () ->
httpPost("/api/hs/office/memberships", usingJsonBody("""
{
"partnerUuid": ${Partner: Test AG},
"memberNumberSuffix": "00",
"validFrom": "2024-10-15",
"membershipFeeBillable": "true"
}
"""))
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
);
return null;
}
}

View File

@ -1,55 +0,0 @@
package net.hostsharing.hsadminng.hs.office.usecases.partner;
import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.hs.office.usecases.UseCase;
import net.hostsharing.hsadminng.hs.office.usecases.UseCaseTest;
import org.springframework.http.HttpStatus;
public class CreatePartner extends UseCase<CreatePartner> {
public CreatePartner(final UseCaseTest testSuite, final String resultAlias) {
super(testSuite, resultAlias);
}
@Override
protected HttpResponse run() {
keep("Person: %{tradeName}", () ->
httpPost("/api/hs/office/persons", usingJsonBody("""
{
"personType": ${personType},
"tradeName": ${tradeName}
}
"""))
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
);
keep("Contact: %{tradeName} - Bord of Directors", () ->
httpPost("/api/hs/office/contacts", usingJsonBody("""
{
"caption": ${contactCaption},
"emailAddresses": {
"main": ${emailAddress}
}
}
"""))
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
);
return httpPost("/api/hs/office/partners", usingJsonBody("""
{
"partnerNumber": ${partnerNumber},
"partnerRel": {
"anchorUuid": ${Person: Hostsharing eG},
"holderUuid": ${Person: %{tradeName}},
"contactUuid": ${Contact: %{tradeName} - Bord of Directors}
},
"details": {
"registrationOffice": "Registergericht Hamburg",
"registrationNumber": "1234567"
}
}
"""))
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON);
}
}

View File

@ -1,25 +0,0 @@
package net.hostsharing.hsadminng.hs.office.usecases.partner;
import net.hostsharing.hsadminng.hs.office.usecases.UseCase;
import net.hostsharing.hsadminng.hs.office.usecases.UseCaseTest;
import org.springframework.http.HttpStatus;
public class DeletePartner extends UseCase<DeletePartner> {
public DeletePartner(final UseCaseTest testSuite) {
super(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")
.given("emailAddress", "bord-of-directors@delete-ag.example.org"));
}
@Override
protected HttpResponse run() {
httpDelete("/api/hs/office/partners/" + uuid("Partner: Delete AG"))
.expecting(HttpStatus.NO_CONTENT);
return null;
}
}