Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/208 Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net> Co-authored-by: Michael Hoennig <michael.hoennig@hostsharing.net> Co-committed-by: Michael Hoennig <michael.hoennig@hostsharing.net>
This commit is contained in:
committed by
Timotheus Pokorra
parent
6d92d80e44
commit
d282885cc9
+15
-1
@@ -285,6 +285,7 @@ tasks.compileJava {
|
||||
configure<SpotlessExtension> {
|
||||
java {
|
||||
// Configure formatting steps
|
||||
|
||||
removeUnusedImports()
|
||||
leadingTabsToSpaces(4)
|
||||
endWithNewline()
|
||||
@@ -429,6 +430,20 @@ tasks.named<JacocoCoverageVerification>("jacocoTestCoverageVerification") {
|
||||
}
|
||||
}
|
||||
|
||||
// HOWTO: run all unit-tests - this is useful in an IDE: gw-test anyTest
|
||||
tasks.register<Test>("anyTest") {
|
||||
useJUnitPlatform()
|
||||
|
||||
testLogging {
|
||||
events("passed", "skipped", "failed", "standardOut", "standardError")
|
||||
showStandardStreams = true
|
||||
}
|
||||
|
||||
group = "verification"
|
||||
description = "runs all unit-tests which do not need a database"
|
||||
|
||||
mustRunAfter(tasks.named("spotlessJava"))
|
||||
}
|
||||
|
||||
// HOWTO: run all unit-tests which don't need a database: gw-test unitTest
|
||||
tasks.register<Test>("unitTest") {
|
||||
@@ -591,7 +606,6 @@ tasks.named<DependencyUpdatesTask>("dependencyUpdates") {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Generate HTML from Markdown scenario-test-reports using Pandoc:
|
||||
tasks.register("convertMarkdownToHtml") {
|
||||
description = "Generates HTML from Markdown scenario-test-reports using Pandoc."
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.accounts;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.val;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.api.ProfileApi;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CurrentLoginUserResource;
|
||||
@@ -13,7 +14,9 @@ import net.hostsharing.hsadminng.accounts.generated.api.v1.model.RbacSubjectReso
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.ScopeResource;
|
||||
import net.hostsharing.hsadminng.config.MessageTranslator;
|
||||
import net.hostsharing.hsadminng.errors.ForbiddenException;
|
||||
import net.hostsharing.hsadminng.errors.Validate;
|
||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePerson;
|
||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
@@ -23,15 +26,18 @@ import net.hostsharing.hsadminng.rbac.subject.RbacSubjectEntity;
|
||||
import net.hostsharing.hsadminng.rbac.subject.RbacSubjectRepository;
|
||||
import net.hostsharing.hsadminng.rbac.subject.RealSubjectEntity;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.validation.ValidationException;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -107,17 +113,19 @@ public class HsProfileController implements ProfileApi {
|
||||
final ProfileInsertResource body
|
||||
) {
|
||||
context.define(); // without assumed roles, otherwise we cannot access the subject anymore
|
||||
final LoginContext originalLoginContext = new LoginContext(context);
|
||||
|
||||
// first create and save the subject to get its UUID
|
||||
val newlySavedSubject = createSubject(body.getNickname());
|
||||
|
||||
// switch to the new subject to get access to its own subject RBAC object
|
||||
context.define("activate newly created self-service subject", null, body.getNickname(), null);
|
||||
|
||||
// afterward, create and save the profile entity with the subject's UUID
|
||||
val newProfileEntity = mapper.map(
|
||||
body, HsProfileEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
|
||||
validateOnCreate(newProfileEntity);
|
||||
validateOnCreate(originalLoginContext, newProfileEntity);
|
||||
|
||||
// switch to the new subject to get access to its own subject RBAC object
|
||||
context.define("activate newly created self-service subject", null, body.getNickname(), null);
|
||||
newProfileEntity.setSubject(em.merge(newlySavedSubject)); // attached to EM by the new subject
|
||||
em.persist(newProfileEntity); // newProfileEntity.uuid == newlySavedSubject.uuid => do not use repository!
|
||||
|
||||
@@ -154,10 +162,11 @@ public class HsProfileController implements ProfileApi {
|
||||
final ProfilePatchResource body
|
||||
) {
|
||||
context.define(); // without assumed roles, otherwise we cannot access the subject anymore
|
||||
final LoginContext originalLoginContext = new LoginContext(context);
|
||||
|
||||
val current = profileRepo.findByUuid(profileUuid).orElseThrow();
|
||||
|
||||
validateBeforePatch(current, body);
|
||||
validateBeforePatch(originalLoginContext, current, body);
|
||||
new HsProfileEntityPatcher(scopeMapper, current).apply(body);
|
||||
validateOnUpdate(current);
|
||||
|
||||
@@ -187,13 +196,15 @@ public class HsProfileController implements ProfileApi {
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
private void validateBeforePatch(final HsProfileEntity current, final ProfilePatchResource body) {
|
||||
private void validateBeforePatch(final LoginContext originalLoginContext, final HsProfileEntity current, final ProfilePatchResource body) {
|
||||
validateReferencedPersonToBeRepresentedByLoginUserPerson(originalLoginContext, current);
|
||||
|
||||
if (!context.isGlobalAdmin() && !current.isActive() && body.getActive())
|
||||
throw new ForbiddenException("Only global admins are allowed to activate an inactive profile");
|
||||
}
|
||||
|
||||
private void validateOnCreate(final HsProfileEntity newProfileEntity) {
|
||||
validateReferencedPersonToBeRepresentedByLoginUserPerson(newProfileEntity);
|
||||
private void validateOnCreate(final LoginContext originalLoginContext, final HsProfileEntity newProfileEntity) {
|
||||
validateReferencedPersonToBeRepresentedByLoginUserPerson(originalLoginContext, newProfileEntity);
|
||||
validateNormalUsersOnlyAccessPublicScopes(newProfileEntity);
|
||||
validateNaturalPersonRequirementOfScopes(newProfileEntity);
|
||||
}
|
||||
@@ -208,20 +219,16 @@ public class HsProfileController implements ProfileApi {
|
||||
validateOwnHsadminProfileMustNotBeRemoved(profileEntity);
|
||||
}
|
||||
|
||||
private void validateReferencedPersonToBeRepresentedByLoginUserPerson(final HsProfileEntity newProfileEntity) {
|
||||
if (context.isGlobalAdmin()) {
|
||||
private void validateReferencedPersonToBeRepresentedByLoginUserPerson(final LoginContext originalLoginContext, final HsProfileEntity profileEntity) {
|
||||
if (originalLoginContext.isGlobalAdmin) {
|
||||
return;
|
||||
}
|
||||
val referredPersonUuid = newProfileEntity.getPerson().getUuid();
|
||||
val currentSubjectUuid = context.fetchCurrentSubjectUuid();
|
||||
val loginPersonUuid = profileRepo.findByUuid(currentSubjectUuid)
|
||||
.map(HsProfileEntity::getPerson)
|
||||
.map(HsOfficePerson::getUuid)
|
||||
.orElseThrow();
|
||||
val referredPersonUuid = profileEntity.getPerson().getUuid();
|
||||
val loginPersonUuid = originalLoginContext.profile.getPerson().getUuid();
|
||||
val representedPersonUuids = realPersonRepo.findPersonsRepresentedByPersonWithUuid(loginPersonUuid)
|
||||
.stream().map(HsOfficePerson::getUuid).toList();
|
||||
if ( !representedPersonUuids.contains(referredPersonUuid)) {
|
||||
throw new ValidationException(
|
||||
throw new ForbiddenException(
|
||||
messageTranslator.translate(
|
||||
"profile.access-denied-to-person-with-uuid-{0}-not-represented-by-currently-logged-in-person",
|
||||
loginPersonUuid));
|
||||
@@ -233,7 +240,7 @@ public class HsProfileController implements ProfileApi {
|
||||
.filter(c -> !c.isPublicAccess() && !context.isGlobalAdmin() )
|
||||
.toList();
|
||||
if (!forbiddenScopes.isEmpty()) {
|
||||
throw new ValidationException(
|
||||
throw new ForbiddenException(
|
||||
messageTranslator.translate(
|
||||
"profile.access-denied-for-scopes-{0}",
|
||||
toDisplay(forbiddenScopes)
|
||||
@@ -330,7 +337,19 @@ public class HsProfileController implements ProfileApi {
|
||||
}
|
||||
|
||||
final BiConsumer<ProfileInsertResource, HsProfileEntity> RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
|
||||
val person = realPersonRepo.findByUuid(resource.getPersonUuid()).orElseThrow(
|
||||
|
||||
Validate.validate("person, person.uuid").exactlyOne(resource.getPerson(), resource.getPersonUuid());
|
||||
if ( resource.getPersonUuid() != null) {
|
||||
entity.setPerson(realPersonRepo.findByUuid(resource.getPersonUuid()).orElseThrow(
|
||||
() -> new NoSuchElementException("cannot find Person by 'person.uuid': " + resource.getPersonUuid())
|
||||
));
|
||||
} else {
|
||||
entity.setPerson(realPersonRepo.save(
|
||||
mapper.map(resource.getPerson(), HsOfficePersonRealEntity.class)
|
||||
) );
|
||||
}
|
||||
|
||||
val person = realPersonRepo.findByUuid(entity.getPerson().getUuid()).orElseThrow(
|
||||
() -> new EntityNotFoundException(
|
||||
messageTranslator.translate("general.{0}-{1}-not-found-or-not-accessible", "personUuid", resource.getPersonUuid())
|
||||
)
|
||||
@@ -339,4 +358,18 @@ public class HsProfileController implements ProfileApi {
|
||||
entity.setScopes(scopeMapper.mapProfileToScopeEntities(resource.getScopes()));
|
||||
entity.setPassword(resource.getPassword());
|
||||
};
|
||||
|
||||
@AllArgsConstructor
|
||||
private class LoginContext {
|
||||
final HsProfileEntity profile;
|
||||
final boolean isGlobalAdmin;
|
||||
|
||||
public LoginContext(final Context context) {
|
||||
val subjectUuid = context.fetchCurrentSubjectUuid();
|
||||
profile = profileRepo.findByUuid(subjectUuid)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
"subject " + context.fetchCurrentSubject() + " has no profile"));
|
||||
isGlobalAdmin = context.isGlobalAdmin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ public class HsProfileEntity implements BaseEntity<HsProfileEntity>, Stringifyab
|
||||
@MapsId
|
||||
@OneToOne(optional = false, fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "uuid", nullable = false, updatable = false, referencedColumnName = "uuid")
|
||||
// Must be the real subject, so that representative persons can access profiles+subjects of represented persons.
|
||||
// Otherwise, we would also need to allow RBAC grants to subject roles.
|
||||
// This also means that each access has to be checked explicitly (same subject or represented subject).
|
||||
private RealSubjectEntity subject;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.EAGER)
|
||||
|
||||
@@ -84,6 +84,8 @@ components:
|
||||
person.uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
person:
|
||||
$ref: '../hs-office/hs-office-person-schemas.yaml#/components/schemas/HsOfficePersonInsert'
|
||||
nickname:
|
||||
type: string
|
||||
pattern: '^[a-z][a-z0-9]{1,8}-[a-z0-9]{1,10}$' # TODO.spec: pattern for login nickname
|
||||
@@ -112,8 +114,11 @@ components:
|
||||
items:
|
||||
$ref: 'scope-schemas.yaml#/components/schemas/Scope'
|
||||
required:
|
||||
- person.uuid
|
||||
- nickname
|
||||
- active
|
||||
# soon we might need to be able to use this:
|
||||
# https://community.smartbear.com/discussions/swaggerostools/defining-conditional-attributes-in-openapi/222410
|
||||
# For now we just describe the conditionally required properties:
|
||||
description:
|
||||
Either `person.uuid` or `person` need to be given.
|
||||
additionalProperties: false
|
||||
|
||||
|
||||
+3
-3
@@ -202,7 +202,7 @@ class HsProfileControllerAcceptanceTest extends ContextBasedTestWithCleanup {
|
||||
.when()
|
||||
.post("http://localhost/api/hs/accounts/profiles")
|
||||
.then().log().all().assertThat()
|
||||
.statusCode(400)
|
||||
.statusCode(403)
|
||||
.contentType("application/json")
|
||||
.body("message", containsString("wird von der eingeloggten Person nicht repräsentiert"));
|
||||
// @formatter:on
|
||||
@@ -246,7 +246,7 @@ class HsProfileControllerAcceptanceTest extends ContextBasedTestWithCleanup {
|
||||
.when()
|
||||
.post("http://localhost/api/hs/accounts/profiles")
|
||||
.then().log().all().assertThat()
|
||||
.statusCode(400)
|
||||
.statusCode(403)
|
||||
.contentType("application/json")
|
||||
.body("message", containsString("Zugriff auf Geltungsbereich verweigert: 'MATRIX:internal', 'SSH:internal'"));
|
||||
// @formatter:on
|
||||
@@ -326,7 +326,7 @@ class HsProfileControllerAcceptanceTest extends ContextBasedTestWithCleanup {
|
||||
.when()
|
||||
.patch("http://localhost/api/hs/accounts/profiles/" + drewProfileUuid)
|
||||
.then().log().all().assertThat()
|
||||
.statusCode(400)
|
||||
.statusCode(403)
|
||||
.contentType("application/json")
|
||||
.body("message", containsString("Zugriff auf Geltungsbereich verweigert: 'MATRIX:internal', 'SSH:internal'"));
|
||||
// @formatter:on
|
||||
|
||||
+7
-2
@@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.accounts.scenarios;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.ScopeResource;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
@@ -9,19 +10,23 @@ import org.apache.commons.lang3.tuple.Pair;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public abstract class BaseProfileUseCase<T extends UseCase<?>> extends UseCase<T> {
|
||||
|
||||
public BaseProfileUseCase(final ScenarioTest testSuite) {
|
||||
protected final FakeLoginUser asLoginUser;
|
||||
|
||||
public BaseProfileUseCase(final ScenarioTest testSuite, final FakeLoginUser asLoginUser) {
|
||||
super(testSuite);
|
||||
this.asLoginUser = asLoginUser;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
protected ScopeResource[] fetchScopeResourcesByDescriptorPairs(final String descriptPairsVarName) {
|
||||
final var requestedScopes = ScenarioTest.getTypedVariable("scopes", Pair[].class);
|
||||
final var existingScopesJson = withTitle("Fetch Available Account Scopes", () ->
|
||||
httpGet("/api/hs/accounts/scopes").expecting(OK).expecting(JSON)
|
||||
httpGet(asGlobalAgent(), "/api/hs/accounts/scopes").expecting(OK).expecting(JSON)
|
||||
).getResponse().body();
|
||||
final var existingScopes = objectMapper.readValue(existingScopesJson, ScopeResource[].class);
|
||||
return Arrays.stream(requestedScopes)
|
||||
|
||||
+8
-7
@@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.accounts.scenarios;
|
||||
|
||||
import io.restassured.http.ContentType;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -8,10 +9,10 @@ import org.springframework.http.HttpStatus;
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class CreateProfile extends BaseProfileUseCase<CreateProfile> {
|
||||
public class CreateProfileForExistingPerson extends BaseProfileUseCase<CreateProfileForExistingPerson> {
|
||||
|
||||
public CreateProfile(final ScenarioTest testSuite) {
|
||||
super(testSuite);
|
||||
public CreateProfileForExistingPerson(final ScenarioTest testSuite, final FakeLoginUser asLoginUser) {
|
||||
super(testSuite, asLoginUser);
|
||||
|
||||
introduction("A set of profile contains the login data for an RBAC subject.");
|
||||
}
|
||||
@@ -20,7 +21,7 @@ public class CreateProfile extends BaseProfileUseCase<CreateProfile> {
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: %{personGivenName} %{personFamilyName}", () ->
|
||||
httpGet("/api/hs/office/persons?name=%{personFamilyName}")
|
||||
httpGet(asLoginUser, "/api/hs/office/persons?name=%{personFamilyName}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In real situations we have more precise measures to find the related person."
|
||||
@@ -31,7 +32,7 @@ public class CreateProfile extends BaseProfileUseCase<CreateProfile> {
|
||||
);
|
||||
|
||||
return obtain("newProfile", () ->
|
||||
httpPost("/api/hs/accounts/profiles", usingJsonBody("""
|
||||
httpPost(asLoginUser, "/api/hs/accounts/profiles", usingJsonBody("""
|
||||
{
|
||||
"person.uuid": ${Person: %{personGivenName} %{personFamilyName}},
|
||||
"nickname": ${nickname},
|
||||
@@ -51,10 +52,10 @@ public class CreateProfile extends BaseProfileUseCase<CreateProfile> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verify(final UseCase<CreateProfile>.HttpResponse response) {
|
||||
protected void verify(final UseCase<CreateProfileForExistingPerson>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify the new Profile",
|
||||
() -> httpGet("/api/hs/accounts/profiles/%{newProfile}")
|
||||
() -> httpGet(asLoginUser, "/api/hs/accounts/profiles/%{newProfile}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
path("uuid").contains("%{newProfile}"),
|
||||
path("nickname").contains("%{nickname}"),
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package net.hostsharing.hsadminng.hs.accounts.scenarios;
|
||||
|
||||
import io.restassured.http.ContentType;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class CreateProfileForNewPerson extends BaseProfileUseCase<CreateProfileForNewPerson> {
|
||||
|
||||
public CreateProfileForNewPerson(final ScenarioTest testSuite, final FakeLoginUser asLoginUser) {
|
||||
super(testSuite, asLoginUser);
|
||||
|
||||
introduction("A set of profile contains the login data for an RBAC subject.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
|
||||
given("resolvedScopes",
|
||||
fetchScopeResourcesByDescriptorPairs("scopes")
|
||||
);
|
||||
|
||||
return obtain("newProfile", () ->
|
||||
httpPost(asLoginUser, "/api/hs/accounts/profiles", usingJsonBody("""
|
||||
{
|
||||
"person": {
|
||||
"personType": "NATURAL_PERSON",
|
||||
"salutation": "Hallo",
|
||||
"title": null,
|
||||
"givenName": ${personGivenName},
|
||||
"familyName": ${personFamilyName}
|
||||
},
|
||||
"nickname": ${nickname},
|
||||
"emailAddress": ${emailAddress},
|
||||
"smsNumber": ${smsNumber},
|
||||
"password": ${password},
|
||||
"totpSecrets": @{totpSecrets},
|
||||
"phonePassword": ${phonePassword},
|
||||
"globalUid": %{globalUid},
|
||||
"globalGid": %{globalGid},
|
||||
"active": %{active},
|
||||
"scopes": @{resolvedScopes}
|
||||
}
|
||||
"""))
|
||||
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verify(final UseCase<CreateProfileForNewPerson>.HttpResponse response) {
|
||||
obtain("Person: %{personGivenName} %{personFamilyName}", () ->
|
||||
httpGet(asLoginUser, "/api/hs/office/persons?name=%{personFamilyName}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
personResponse -> personResponse.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In real situations we have more precise measures to find the related person."
|
||||
);
|
||||
|
||||
verify(
|
||||
"Verify the new Profile",
|
||||
() -> httpGet(asLoginUser, "/api/hs/accounts/profiles/%{newProfile}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
path("uuid").contains("%{newProfile}"),
|
||||
path("nickname").contains("%{nickname}"),
|
||||
path("person.uuid").contains("%{Person: %{personGivenName} %{personFamilyName}}"),
|
||||
path("totpSecrets").contains("@{totpSecrets}")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.bearerTemplate;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.resolve;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.TemplateResolver.Resolver.DROP_COMMENTS;
|
||||
@@ -24,7 +25,7 @@ public class CurrentLoginUser extends UseCase<CurrentLoginUser> {
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: %{personGivenName}", () ->
|
||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{personGivenName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/persons?name=" + uriEncoded("%{personGivenName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
|
||||
+82
-11
@@ -13,6 +13,10 @@ import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInfo;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.as;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
|
||||
class ProfileScenarioTests extends ScenarioTest {
|
||||
|
||||
@@ -35,7 +39,7 @@ class ProfileScenarioTests extends ScenarioTest {
|
||||
.given("subjectName", "superuser-fran@hostsharing.net")
|
||||
.given("assumedRoles", "rbactest.package#xxx00:ADMIN;rbactest.package#yyy00:ADMIN")
|
||||
.given("expectedToBeGlobalAdmin", true)
|
||||
.doRun()
|
||||
.thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
}
|
||||
@@ -53,7 +57,7 @@ class ProfileScenarioTests extends ScenarioTest {
|
||||
.given("subjectName", "superuser-fran@hostsharing.net")
|
||||
.given("personGivenName", "Fran")
|
||||
.given("expectedToBeGlobalAdmin", true)
|
||||
.doRun()
|
||||
.thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
}
|
||||
@@ -65,9 +69,11 @@ class ProfileScenarioTests extends ScenarioTest {
|
||||
|
||||
@Test
|
||||
@Order(1010)
|
||||
@Produces(explicitly = "Profile: firby-susan", implicitly = { "Person: Susan Firby" })
|
||||
@Produces(
|
||||
explicitly = "Profile: susan-firby",
|
||||
implicitly = {"Person: Susan Firby"})
|
||||
void shouldCreateInitialProfileForExistingNaturalPerson() {
|
||||
new CreateProfile(scenarioTest)
|
||||
new CreateProfileForExistingPerson(scenarioTest, asGlobalAgent())
|
||||
// to find a specific existing person
|
||||
.given("personFamilyName", "Firby")
|
||||
.given("personGivenName", "Susan")
|
||||
@@ -86,30 +92,95 @@ class ProfileScenarioTests extends ScenarioTest {
|
||||
"scopes", Array.of(
|
||||
Pair.of("HSADMIN", "prod")
|
||||
))
|
||||
.doRun()
|
||||
.thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1020)
|
||||
@Requires("Profile: firby-susan")
|
||||
void shouldUpdateProfile() {
|
||||
new UpdateProfile(scenarioTest)
|
||||
@Requires("Profile: susan-firby")
|
||||
void naturalPersonShouldBeAbleToUpdateTheirOwnProfile() {
|
||||
new UpdateProfile(scenarioTest, as("firby-susan"))
|
||||
// the profile to update
|
||||
.given("profileUuid", "%{Profile: firby-susan}")
|
||||
.given("profileUuid", "%{Profile: susan-firby}")
|
||||
// updated profile
|
||||
.given("active", false)
|
||||
.given("totpSecrets", Array.of("initialSecret", "additionalSecret"))
|
||||
.given("emailAddress", "susan.firby@example.org")
|
||||
.given("password", "my new raw password")
|
||||
.given("phonePassword", "securePass987")
|
||||
.given("smsNumber", "+49987654321")
|
||||
.given("scopes", Array.of(Pair.of("HSADMIN", "prod"), Pair.of("SSH", "external")))
|
||||
.thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1100)
|
||||
@Produces(
|
||||
explicitly = "Profile: peter-newman",
|
||||
implicitly = {"Person: Peter Newman"})
|
||||
void shouldCreateInitialProfileForNewNaturalPerson() {
|
||||
new CreateProfileForNewPerson(scenarioTest, asGlobalAgent())
|
||||
// to find a specific existing person
|
||||
.given("personFamilyName", "Newman")
|
||||
.given("personGivenName", "Peter")
|
||||
// a login name, to be stored in the new RBAC subject
|
||||
.given("nickname", "newman-peter")
|
||||
// initial profile
|
||||
.given("emailAddress", "peter.newman@example.com")
|
||||
.given("smsNumber", "+49123456789")
|
||||
.given("password", "my raw password")
|
||||
.given("totpSecrets", Array.of("initialSecret"))
|
||||
.given("phonePassword", "securePass123")
|
||||
.given("globalUid", 21012)
|
||||
.given("globalGid", 21012)
|
||||
.given("active", true)
|
||||
.given("scopes", Array.of(Pair.of("HSADMIN", "prod")))
|
||||
.thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1110)
|
||||
@Requires("Profile: peter-newman")
|
||||
void newNaturalPersonShouldBeAbleToUpdateTheirOwnProfile() {
|
||||
new UpdateProfile(scenarioTest, as("newman-peter"))
|
||||
// the profile to update
|
||||
.given("profileUuid", "%{Profile: peter-newman}")
|
||||
// updated profile
|
||||
.given("active", false)
|
||||
.given("totpSecrets", Array.of("initialSecret", "additionalSecret"))
|
||||
.given("emailAddress", "peter.newman@example.org")
|
||||
.given("password", "my new raw password")
|
||||
.given("phonePassword", "securePass987")
|
||||
.given("smsNumber", "+49987654321")
|
||||
.given(
|
||||
"scopes", Array.of(
|
||||
Pair.of("HSADMIN", "prod"),
|
||||
Pair.of("SSH", "internal")
|
||||
Pair.of("SSH", "external")
|
||||
))
|
||||
.doRun();
|
||||
.thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1120)
|
||||
@Requires({"Profile: peter-newman", "Profile: susan-firby"})
|
||||
// Usually, scenario tests just test positive cases, but in the case of account profiles, security is extra important,
|
||||
// thus I've added also some negative cases like this one for documentation reasons.
|
||||
// More negative cases are tested in "so-called" Acceptance and in RestTests.
|
||||
void anotherNaturalPersonShouldNotBeAbleToUpdateOthersProfile() {
|
||||
new UpdateProfile(scenarioTest, as("firby-susan"))
|
||||
// the profile to update
|
||||
.given("profileUuid", "%{Profile: peter-newman}")
|
||||
// updated profile
|
||||
.given("active", false)
|
||||
.given("totpSecrets", Array.of("initialSecret", "additionalSecret"))
|
||||
.given("emailAddress", "peter.newman@example.org")
|
||||
.given("password", "my new raw password")
|
||||
.given("phonePassword", "securePass987")
|
||||
.given("smsNumber", "+49987654321")
|
||||
.given("scopes", Array.of(Pair.of("HSADMIN", "prod"), Pair.of("SSH", "external")))
|
||||
.thenExpect(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
package net.hostsharing.hsadminng.hs.accounts.scenarios;
|
||||
|
||||
import io.restassured.http.ContentType;
|
||||
import lombok.val;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static org.assertj.core.api.Fail.fail;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class UpdateProfile extends BaseProfileUseCase<UpdateProfile> {
|
||||
|
||||
public UpdateProfile(final ScenarioTest testSuite) {
|
||||
super(testSuite);
|
||||
public UpdateProfile(final ScenarioTest testSuite, final FakeLoginUser asLoginUser) {
|
||||
super(testSuite, asLoginUser);
|
||||
|
||||
introduction("A set of profile contains the login data for an RBAC subject.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
protected HttpResponse run(final HttpStatus expectedStatus) {
|
||||
|
||||
given("resolvedScopes",
|
||||
fetchScopeResourcesByDescriptorPairs("scopes")
|
||||
);
|
||||
|
||||
withTitle("Patch the Changes to the existing Profile", () ->
|
||||
httpPatch("/api/hs/accounts/profiles/%{profileUuid}", usingJsonBody("""
|
||||
return withTitle("Patch the Changes to the existing Profile", () -> {
|
||||
val response = httpPatch(
|
||||
asLoginUser, "/api/hs/accounts/profiles/%{profileUuid}", usingJsonBody("""
|
||||
{
|
||||
"active": %{active},
|
||||
"totpSecrets": @{totpSecrets},
|
||||
@@ -34,19 +38,24 @@ public class UpdateProfile extends BaseProfileUseCase<UpdateProfile> {
|
||||
"scopes": @{resolvedScopes}
|
||||
}
|
||||
"""))
|
||||
.reportWithResponse().expecting(HttpStatus.OK).expecting(ContentType.JSON)
|
||||
.extractValue("nickname", "nickname")
|
||||
.extractValue("totpSecrets", "totpSecrets")
|
||||
);
|
||||
.reportWithResponse().expecting(expectedStatus);
|
||||
|
||||
return null;
|
||||
return switch (expectedStatus) {
|
||||
case OK -> response.expecting(ContentType.JSON)
|
||||
.extractValue("nickname", "nickname")
|
||||
.extractValue("totpSecrets", "totpSecrets");
|
||||
case FORBIDDEN -> response.expecting(ContentType.JSON);
|
||||
default -> fail("unexpected response: " + response);
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verify(final UseCase<UpdateProfile>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify the Patched Profile",
|
||||
() -> httpGet("/api/hs/accounts/profiles/%{profileUuid}")
|
||||
() -> httpGet(asLoginUser, "/api/hs/accounts/profiles/%{profileUuid}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
path("uuid").contains("%{newProfile}"),
|
||||
path("nickname").contains("%{nickname}"),
|
||||
|
||||
+45
-76
@@ -51,6 +51,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInfo;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
class HsOfficeScenarioTests extends ScenarioTest {
|
||||
|
||||
@@ -104,8 +105,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("officePhoneNumber", "+49 40 654321-0")
|
||||
.given("emailAddress", "hamburg@test-ag.example.org")
|
||||
.given("registrationOffice", "Registergericht Hamburg")
|
||||
.given("registrationNumber", "1234567")
|
||||
.doRun()
|
||||
.given("registrationNumber", "1234567").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -132,8 +132,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("emailAddress", "michelle.matthieu@example.org")
|
||||
.given("birthday", "1951-03-25")
|
||||
.given("birthPlace", "Neustadt a.d.R.")
|
||||
.given("birthName", "Eichbaum")
|
||||
.doRun()
|
||||
.given("birthName", "Eichbaum").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -155,8 +154,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
"country": "Germany"
|
||||
""")
|
||||
.given("representativePhoneNumber", "+49 40 123456")
|
||||
.given("representativeEMailAddress", "tracy.trust@example.org")
|
||||
.doRun()
|
||||
.given("representativeEMailAddress", "tracy.trust@example.org").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -170,8 +168,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("operationsContactFamilyName", "Krause")
|
||||
.given("operationsContactGivenName", "Dennis")
|
||||
.given("operationsContactPhoneNumber", "+49 9932 587741")
|
||||
.given("operationsContactEMailAddress", "dennis.krause@example.org")
|
||||
.doRun()
|
||||
.given("operationsContactEMailAddress", "dennis.krause@example.org").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -180,16 +177,14 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
@Requires("Operations-Contact: Dennis Krause for Test AG")
|
||||
void shouldRemoveOperationsContactFromPartner() {
|
||||
new RemoveOperationsContactFromPartner(scenarioTest)
|
||||
.given("operationsContactPerson", "Dennis Krause")
|
||||
.doRun();
|
||||
.given("operationsContactPerson", "Dennis Krause").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1090)
|
||||
void shouldDeletePartner() {
|
||||
new DeletePartner(scenarioTest)
|
||||
.given("partnerNumber", "P-31020")
|
||||
.doRun();
|
||||
.given("partnerNumber", "P-31020").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,8 +199,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
void shouldAmendContactData() {
|
||||
new AmendContactData(scenarioTest)
|
||||
.given("partnerName", "Matthieu")
|
||||
.given("newEmailAddress", "michelle@matthieu.example.org")
|
||||
.doRun();
|
||||
.given("newEmailAddress", "michelle@matthieu.example.org").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -215,8 +209,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
new AddPhoneNumberToContactData(scenarioTest)
|
||||
.given("partnerName", "Matthieu")
|
||||
.given("phoneNumberKeyToAdd", "mobile")
|
||||
.given("phoneNumberToAdd", "+49 152 1234567")
|
||||
.doRun();
|
||||
.given("phoneNumberToAdd", "+49 152 1234567").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -225,8 +218,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
void shouldRemovePhoneNumberFromContactData() {
|
||||
new RemovePhoneNumberFromContactData(scenarioTest)
|
||||
.given("partnerName", "Matthieu")
|
||||
.given("phoneNumberKeyToRemove", "office")
|
||||
.doRun();
|
||||
.given("phoneNumberKeyToRemove", "office").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -247,8 +239,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
"country": "China"
|
||||
""")
|
||||
.given("newOfficePhoneNumber", "++15 999 654321")
|
||||
.given("newEmailAddress", "norden@test-ag.example.org")
|
||||
.doRun();
|
||||
.given("newEmailAddress", "norden@test-ag.example.org").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,8 +254,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
void shouldUpdatePersonData() {
|
||||
new ShouldUpdatePersonData(scenarioTest)
|
||||
.given("oldFamilyName", "Matthieu")
|
||||
.given("newFamilyName", "Matthieu-Zhang")
|
||||
.doRun();
|
||||
.given("newFamilyName", "Matthieu-Zhang").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,14 +268,14 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
@Requires("Partner: P-31011 - Michelle Matthieu")
|
||||
@Produces("Debitor: D-3101100 - Michelle Matthieu")
|
||||
void shouldCreateSelfDebitorForPartnerWithIdenticalContactData() {
|
||||
// TODO.impl: could be assigned automatically but is not yet
|
||||
new CreateSelfDebitorForPartnerWithIdenticalContactData(scenarioTest)
|
||||
.given("partnerNumber", "P-31011")
|
||||
.given("debitorNumberSuffix", "00") // TODO.impl: could be assigned automatically but is not yet
|
||||
.given("billable", true)
|
||||
.given("vatBusiness", false)
|
||||
.given("vatReverseCharge", false)
|
||||
.given("defaultPrefix", "mim")
|
||||
.doRun()
|
||||
.given("defaultPrefix", "mim").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -294,6 +284,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
@Requires("Partner: P-31010 - Test AG")
|
||||
@Produces("Debitor: D-3101000 - Test AG - main debitor")
|
||||
void shouldCreateSelfDebitorForPartnerWithDistinctContactData() {
|
||||
// TODO.impl: could be assigned automaticallybut is not yet
|
||||
new CreateSelfDebitorForPartner(scenarioTest)
|
||||
.given("partnerPersonTradeName", "Test AG")
|
||||
.given("billingContactCaption", "Test AG - billing department")
|
||||
@@ -304,8 +295,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("vatCountryCode", "DE")
|
||||
.given("vatBusiness", true)
|
||||
.given("vatReverseCharge", false)
|
||||
.given("defaultPrefix", "tst")
|
||||
.doRun()
|
||||
.given("defaultPrefix", "tst").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -324,8 +314,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("vatCountryCode", "DE")
|
||||
.given("vatBusiness", true)
|
||||
.given("vatReverseCharge", false)
|
||||
.given("defaultPrefix", "tsx")
|
||||
.doRun()
|
||||
.given("defaultPrefix", "tsx").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -344,8 +333,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("vatCountryCode", "DE")
|
||||
.given("vatBusiness", true)
|
||||
.given("vatReverseCharge", false)
|
||||
.given("defaultPrefix", "tsy")
|
||||
.doRun()
|
||||
.given("defaultPrefix", "tsy").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -356,8 +344,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
void shouldDeleteDebitor() {
|
||||
new DeleteDebitor(scenarioTest)
|
||||
.given("partnerNumber", "P-31020")
|
||||
.given("debitorSuffix", "02")
|
||||
.doRun();
|
||||
.given("debitorSuffix", "02").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -367,8 +354,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
void shouldNotDeleteDefaultDebitor() {
|
||||
new DontDeleteDefaultDebitor(scenarioTest)
|
||||
.given("partnerNumber", "P-31010")
|
||||
.given("debitorSuffix", "00")
|
||||
.doRun();
|
||||
.given("debitorSuffix", "00").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,6 +368,9 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
@Requires("Debitor: D-3101000 - Test AG - main debitor")
|
||||
@Produces("SEPA-Mandate: Test AG")
|
||||
void shouldCreateSepaMandateForDebitor() {
|
||||
// existing debitor
|
||||
// new sepa-mandate
|
||||
// new bank-account
|
||||
new CreateSepaMandateForDebitor(scenarioTest)
|
||||
// existing debitor
|
||||
.given("debitorNumber", "D-3101000")
|
||||
@@ -394,8 +383,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
// new bank-account
|
||||
.given("bankAccountHolder", "Test AG - debit bank account")
|
||||
.given("bankAccountIBAN", "DE02701500000000594937")
|
||||
.given("bankAccountBIC", "SSKMDEMM")
|
||||
.doRun()
|
||||
.given("bankAccountBIC", "SSKMDEMM").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -405,8 +393,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
void shouldInvalidateSepaMandateForDebitor() {
|
||||
new InvalidateSepaMandateForDebitor(scenarioTest)
|
||||
.given("bankAccountIBAN", "DE02701500000000594937")
|
||||
.given("mandateValidTo", "2025-09-30")
|
||||
.doRun();
|
||||
.given("mandateValidTo", "2025-09-30").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -414,8 +401,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
@Requires("SEPA-Mandate: Test AG")
|
||||
void shouldFinallyDeleteSepaMandateForDebitor() {
|
||||
new FinallyDeleteSepaMandateForDebitor(scenarioTest)
|
||||
.given("bankAccountIBAN", "DE02701500000000594937")
|
||||
.doRun();
|
||||
.given("bankAccountIBAN", "DE02701500000000594937").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,8 +419,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("partnerName", "Test AG")
|
||||
.given("validFrom", "2020-10-15")
|
||||
.given("newStatus", "ACTIVE")
|
||||
.given("membershipFeeBillable", "true")
|
||||
.doRun()
|
||||
.given("membershipFeeBillable", "true").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -446,8 +431,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
new CancelMembership(scenarioTest)
|
||||
.given("memberNumber", "M-3101000")
|
||||
.given("validTo", "2023-12-31")
|
||||
.given("newStatus", "CANCELLED")
|
||||
.doRun()
|
||||
.given("newStatus", "CANCELLED").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -461,8 +445,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("memberNumberSuffix", "01")
|
||||
.given("validFrom", "2025-02-24")
|
||||
.given("newStatus", "ACTIVE")
|
||||
.given("membershipFeeBillable", "true")
|
||||
.doRun()
|
||||
.given("membershipFeeBillable", "true").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
}
|
||||
@@ -482,8 +465,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("reference", "sign 2024-01-15")
|
||||
.given("shareCount", 100)
|
||||
.given("comment", "Signing the Membership")
|
||||
.given("transactionDate", "2024-01-15")
|
||||
.doRun();
|
||||
.given("transactionDate", "2024-01-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -493,8 +475,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
new CreateCoopSharesRevertTransaction(scenarioTest)
|
||||
.given("memberNumber", "M-3101000")
|
||||
.given("comment", "reverting some incorrect transaction")
|
||||
.given("dateOfIncorrectTransaction", "2024-02-15")
|
||||
.doRun();
|
||||
.given("dateOfIncorrectTransaction", "2024-02-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -507,8 +488,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("reference", "cancel 2024-01-15")
|
||||
.given("sharesToCancel", 8)
|
||||
.given("comment", "Cancelling 8 Shares")
|
||||
.given("transactionDate", "2024-02-15")
|
||||
.doRun();
|
||||
.given("transactionDate", "2024-02-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,8 +507,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("reference", "sign 2024-01-15")
|
||||
.given("assetValue", 100 * 64)
|
||||
.given("comment", "disposal for initial shares")
|
||||
.given("transactionDate", "2024-01-15")
|
||||
.doRun();
|
||||
.given("transactionDate", "2024-01-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -538,8 +517,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
new CreateCoopAssetsRevertSimpleTransaction(scenarioTest)
|
||||
.given("memberNumber", "M-3101000")
|
||||
.given("comment", "reverting some incorrect transaction")
|
||||
.given("dateOfIncorrectTransaction", "2024-02-15")
|
||||
.doRun();
|
||||
.given("dateOfIncorrectTransaction", "2024-02-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -552,8 +530,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("reference", "cancel 2024-01-15")
|
||||
.given("valueToDisburse", 8 * 64)
|
||||
.given("comment", "disbursal according to shares cancellation")
|
||||
.given("transactionDate", "2024-02-15")
|
||||
.doRun();
|
||||
.given("transactionDate", "2024-02-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -567,8 +544,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("reference", "transfer 2024-12-31")
|
||||
.given("valueToTransfer", 2 * 64)
|
||||
.given("comment", "transfer assets from M-3101000 to M-4303000")
|
||||
.given("transactionDate", "2024-12-31")
|
||||
.doRun();
|
||||
.given("transactionDate", "2024-12-31").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -580,8 +556,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("adoptingMemberNumber", "M-4303000")
|
||||
.given("transferredValue", 2 * 64)
|
||||
.given("comment", "reverting some incorrect transfer transaction")
|
||||
.given("dateOfIncorrectTransaction", "2024-02-15")
|
||||
.doRun();
|
||||
.given("dateOfIncorrectTransaction", "2024-02-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -593,8 +568,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("reference", "cancel 2024-01-15")
|
||||
.given("valueToClear", 2 * 64)
|
||||
.given("comment", "clearing according to members debt")
|
||||
.given("transactionDate", "2024-02-15")
|
||||
.doRun();
|
||||
.given("transactionDate", "2024-02-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -606,8 +580,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("reference", "cancel 2024-01-15")
|
||||
.given("valueLost", 2 * 64)
|
||||
.given("comment", "assign balance sheet loss")
|
||||
.given("transactionDate", "2024-02-15")
|
||||
.doRun();
|
||||
.given("transactionDate", "2024-02-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -619,8 +592,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("reference", "cancel 2024-01-15")
|
||||
.given("valueForLimitation", 2 * 64)
|
||||
.given("comment", "adjust coop ")
|
||||
.given("transactionDate", "2024-02-15")
|
||||
.doRun();
|
||||
.given("transactionDate", "2024-02-15").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,14 +606,14 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
@Requires("Person: Test AG")
|
||||
@Produces("Subscription: Michael Miller to operations-announce")
|
||||
void shouldSubscribeNewPersonAndContactToMailinglist() {
|
||||
// TODO.spec: do we need the personType? or is an operational contact always a natural person? what about distribution lists?
|
||||
new SubscribeNewPersonAndContactToMailinglist(scenarioTest)
|
||||
// TODO.spec: do we need the personType? or is an operational contact always a natural person? what about distribution lists?
|
||||
.given("partnerPersonTradeName", "Test AG")
|
||||
.given("subscriberFamilyName", "Miller")
|
||||
.given("subscriberGivenName", "Michael")
|
||||
.given("subscriberEMailAddress", "michael.miller@example.org")
|
||||
.given("mailingList", "operations-announce")
|
||||
.doRun()
|
||||
.given("mailingList", "operations-announce").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -655,8 +627,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
.given("subscriberFamilyName", "Miller")
|
||||
.given("subscriberGivenName", "Michael")
|
||||
.given("subscriberEMailAddress", "michael.miller@example.org")
|
||||
.given("mailingList", "operations-discussion")
|
||||
.doRun()
|
||||
.given("mailingList", "operations-discussion").thenExpect(HttpStatus.OK)
|
||||
.keep();
|
||||
}
|
||||
|
||||
@@ -666,8 +637,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
void shouldUnsubscribePersonAndContactFromMailinglist() {
|
||||
new UnsubscribeFromMailinglist(scenarioTest)
|
||||
.given("mailingList", "operations-announce")
|
||||
.given("subscriberEMailAddress", "michael.miller@example.org")
|
||||
.doRun();
|
||||
.given("subscriberEMailAddress", "michael.miller@example.org").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,8 +664,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
"country": "Germany"
|
||||
""")
|
||||
.given("communityOfHeirsOfficePhoneNumber", "+49 40 666666")
|
||||
.given("communityOfHeirsEmailAddress", "lena.stadland@example.org")
|
||||
.doRun();
|
||||
.given("communityOfHeirsEmailAddress", "lena.stadland@example.org").thenExpect(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -6,6 +6,7 @@ import org.springframework.http.HttpStatus;
|
||||
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class AddPhoneNumberToContactData extends UseCase<AddPhoneNumberToContactData> {
|
||||
@@ -19,14 +20,14 @@ public class AddPhoneNumberToContactData extends UseCase<AddPhoneNumberToContact
|
||||
|
||||
obtain(
|
||||
"partnerContactUuid",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].contact.uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
withTitle("Patch the Additional Phone-Number into the Contact", () ->
|
||||
httpPatch("/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||
return withTitle("Patch the Additional Phone-Number into the Contact", () ->
|
||||
httpPatch(asGlobalAgent(), "/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||
{
|
||||
"phoneNumbers": {
|
||||
${phoneNumberKeyToAdd}: ${phoneNumberToAdd}
|
||||
@@ -35,15 +36,13 @@ public class AddPhoneNumberToContactData extends UseCase<AddPhoneNumberToContact
|
||||
"""))
|
||||
.expecting(HttpStatus.OK)
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verify(final UseCase<AddPhoneNumberToContactData>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify if the New Phone Number Got Added",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].contact.phoneNumbers.%{phoneNumberKeyToAdd}").contains("%{phoneNumberToAdd}")
|
||||
);
|
||||
|
||||
+4
-5
@@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class AmendContactData extends UseCase<AmendContactData> {
|
||||
@@ -17,14 +18,14 @@ public class AmendContactData extends UseCase<AmendContactData> {
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("partnerContactUuid", () ->
|
||||
httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].contact.uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
withTitle("Patch the New Phone Number Into the Contact", () ->
|
||||
httpPatch("/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||
return withTitle("Patch the New Phone Number Into the Contact", () ->
|
||||
httpPatch(asGlobalAgent(), "/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||
{
|
||||
"caption": ${newContactCaption???},
|
||||
"postalAddress": {
|
||||
@@ -40,7 +41,5 @@ public class AmendContactData extends UseCase<AmendContactData> {
|
||||
"""))
|
||||
.expecting(HttpStatus.OK)
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class RemovePhoneNumberFromContactData extends UseCase<RemovePhoneNumberFromContactData> {
|
||||
@@ -18,14 +19,14 @@ public class RemovePhoneNumberFromContactData extends UseCase<RemovePhoneNumberF
|
||||
|
||||
obtain(
|
||||
"partnerContactUuid",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].contact.uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
withTitle("Patch the Additional Phone-Number into the Contact", () ->
|
||||
httpPatch("/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||
return withTitle("Patch the Additional Phone-Number into the Contact", () ->
|
||||
httpPatch(asGlobalAgent(), "/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||
{
|
||||
"phoneNumbers": {
|
||||
${phoneNumberKeyToRemove}: NULL
|
||||
@@ -34,15 +35,13 @@ public class RemovePhoneNumberFromContactData extends UseCase<RemovePhoneNumberF
|
||||
"""))
|
||||
.expecting(HttpStatus.OK)
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verify(final UseCase<RemovePhoneNumberFromContactData>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify if the New Phone Number Got Added",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].contact.phoneNumbers.%{phoneNumberKeyToRemove}").doesNotExist()
|
||||
);
|
||||
|
||||
+6
-7
@@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -17,14 +18,14 @@ public class ReplaceContactData extends UseCase<ReplaceContactData> {
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("partnerRelationUuid", () ->
|
||||
httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
obtain("Contact: %{newContactCaption}", () ->
|
||||
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/contacts", usingJsonBody("""
|
||||
{
|
||||
"caption": ${newContactCaption},
|
||||
"postalAddress": {
|
||||
@@ -44,23 +45,21 @@ public class ReplaceContactData extends UseCase<ReplaceContactData> {
|
||||
"(currently `firm`, `name`, `co`, `street`, `zipcode`, `city`, `country`) " +
|
||||
"its values might not appear in external systems.");
|
||||
|
||||
withTitle("Replace the Contact-Reference in the Partner-Relation", () ->
|
||||
httpPatch("/api/hs/office/relations/%{partnerRelationUuid}", usingJsonBody("""
|
||||
return withTitle("Replace the Contact-Reference in the Partner-Relation", () ->
|
||||
httpPatch(asGlobalAgent(), "/api/hs/office/relations/%{partnerRelationUuid}", usingJsonBody("""
|
||||
{
|
||||
"contact.uuid": ${Contact: %{newContactCaption}}
|
||||
}
|
||||
"""))
|
||||
.expecting(OK)
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verify(final UseCase<ReplaceContactData>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify if the Contact-Relation Got Replaced in the Partner-Relation",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].contact.caption").contains("%{newContactCaption}")
|
||||
);
|
||||
|
||||
+5
-4
@@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.office.scenarios.person.CreatePerson;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -23,14 +24,14 @@ public class CreateExternalDebitorForPartner extends UseCase<CreateExternalDebit
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: %{partnerPersonTradeName}", () ->
|
||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
obtain("BankAccount: Billing GmbH - refund bank account", () ->
|
||||
httpPost("/api/hs/office/bankaccounts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/bankaccounts", usingJsonBody("""
|
||||
{
|
||||
"holder": "Billing GmbH - refund bank account",
|
||||
"iban": "DE02120300000000202051",
|
||||
@@ -41,7 +42,7 @@ public class CreateExternalDebitorForPartner extends UseCase<CreateExternalDebit
|
||||
);
|
||||
|
||||
obtain("Contact: Billing GmbH - Test AG billing", () ->
|
||||
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/contacts", usingJsonBody("""
|
||||
{
|
||||
"caption": "Billing GmbH, billing for Test AG",
|
||||
"emailAddresses": {
|
||||
@@ -52,7 +53,7 @@ public class CreateExternalDebitorForPartner extends UseCase<CreateExternalDebit
|
||||
.expecting(CREATED).expecting(JSON)
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/debitors", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/debitors", usingJsonBody("""
|
||||
{
|
||||
"debitorRel": {
|
||||
"anchor.uuid": ${Person: %{partnerPersonTradeName}},
|
||||
|
||||
+5
-4
@@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -16,14 +17,14 @@ public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPar
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
obtain("partnerPersonUuid", () ->
|
||||
httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].holder.uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
obtain("BankAccount: Test AG - refund bank account", () ->
|
||||
httpPost("/api/hs/office/bankaccounts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/bankaccounts", usingJsonBody("""
|
||||
{
|
||||
"holder": "Test AG - refund bank account",
|
||||
"iban": "DE88100900001234567892",
|
||||
@@ -34,7 +35,7 @@ public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPar
|
||||
);
|
||||
|
||||
obtain("Contact: Test AG - billing department", () ->
|
||||
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/contacts", usingJsonBody("""
|
||||
{
|
||||
"caption": ${billingContactCaption},
|
||||
"emailAddresses": {
|
||||
@@ -45,7 +46,7 @@ public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPar
|
||||
.expecting(CREATED).expecting(JSON)
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/debitors", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/debitors", usingJsonBody("""
|
||||
{
|
||||
"debitorRel": {
|
||||
"anchor.uuid": ${partnerPersonUuid},
|
||||
|
||||
+3
-2
@@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
|
||||
public class CreateSelfDebitorForPartnerWithIdenticalContactData
|
||||
@@ -17,13 +18,13 @@ public class CreateSelfDebitorForPartnerWithIdenticalContactData
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
withTitle("Determine Partner-Person UUID", () ->
|
||||
httpGet("/api/hs/office/partners/" + uriEncoded("%{partnerNumber}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/partners/" + uriEncoded("%{partnerNumber}"))
|
||||
.reportWithResponse().expecting(HttpStatus.OK).expecting(JSON)
|
||||
.extractUuidAlias("partnerRel.holder.uuid", "partnerPersonUuid")
|
||||
.extractUuidAlias("partnerRel.contact.uuid", "partnerContactUuid")
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/debitors", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/debitors", usingJsonBody("""
|
||||
{
|
||||
"debitorRel": {
|
||||
"anchor.uuid": ${partnerPersonUuid},
|
||||
|
||||
+4
-3
@@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -17,13 +18,13 @@ public class CreateSepaMandateForDebitor extends UseCase<CreateSepaMandateForDeb
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Debitor: Test AG - main debitor", () ->
|
||||
httpGet("/api/hs/office/debitors/%{debitorNumber}")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/debitors/%{debitorNumber}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.getFromBody("uuid")
|
||||
);
|
||||
|
||||
obtain("BankAccount: Test AG - debit bank account", () ->
|
||||
httpPost("/api/hs/office/bankaccounts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/bankaccounts", usingJsonBody("""
|
||||
{
|
||||
"holder": ${bankAccountHolder},
|
||||
"iban": ${bankAccountIBAN},
|
||||
@@ -33,7 +34,7 @@ public class CreateSepaMandateForDebitor extends UseCase<CreateSepaMandateForDeb
|
||||
.expecting(CREATED).expecting(JSON)
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/sepamandates", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/sepamandates", usingJsonBody("""
|
||||
{
|
||||
"debitor.uuid": ${Debitor: Test AG - main debitor},
|
||||
"bankAccount.uuid": ${BankAccount: Test AG - debit bank account},
|
||||
|
||||
+4
-3
@@ -4,6 +4,8 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
|
||||
public class DeleteDebitor extends UseCase<DeleteDebitor> {
|
||||
|
||||
public DeleteDebitor(final ScenarioTest testSuite) {
|
||||
@@ -24,10 +26,9 @@ public class DeleteDebitor extends UseCase<DeleteDebitor> {
|
||||
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
withTitle("Delete the Debitor using its UUID", () ->
|
||||
httpDelete("/api/hs/office/debitors/&{Debitor: Test AG - delete debitor}")
|
||||
return withTitle("Delete the Debitor using its UUID", () ->
|
||||
httpDelete(asGlobalAgent(), "/api/hs/office/debitors/&{Debitor: Test AG - delete debitor}")
|
||||
.expecting(HttpStatus.NO_CONTENT)
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -4,6 +4,8 @@ import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
|
||||
public class DontDeleteDefaultDebitor extends UseCase<DontDeleteDefaultDebitor> {
|
||||
|
||||
public DontDeleteDefaultDebitor(final ScenarioTest testSuite) {
|
||||
@@ -12,7 +14,7 @@ public class DontDeleteDefaultDebitor extends UseCase<DontDeleteDefaultDebitor>
|
||||
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
httpDelete("/api/hs/office/debitors/&{Debitor: Test AG - main debitor}")
|
||||
httpDelete(asGlobalAgent(), "/api/hs/office/debitors/&{Debitor: Test AG - main debitor}")
|
||||
// TODO.spec: should be CONFLICT or CLIENT_ERROR for Debitor "00" - but how to delete Partners?
|
||||
.expecting(HttpStatus.NO_CONTENT);
|
||||
return null;
|
||||
|
||||
+4
-2
@@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class FinallyDeleteSepaMandateForDebitor extends UseCase<FinallyDeleteSepaMandateForDebitor> {
|
||||
@@ -17,14 +18,15 @@ public class FinallyDeleteSepaMandateForDebitor extends UseCase<FinallyDeleteSep
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("SEPA-Mandate: %{bankAccountIBAN}", () ->
|
||||
httpGet("/api/hs/office/sepamandates?iban=&{bankAccountIBAN}")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/sepamandates?iban=&{bankAccountIBAN}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"With production data, the bank-account could be used in multiple SEPA-mandates, make sure to use the right one!"
|
||||
);
|
||||
|
||||
// TODO.spec: When to allow actual deletion of SEPA-mandates? Add constraint accordingly.
|
||||
return withTitle("Delete the SEPA-Mandate by its UUID", () -> httpDelete("/api/hs/office/sepamandates/&{SEPA-Mandate: %{bankAccountIBAN}}")
|
||||
return withTitle("Delete the SEPA-Mandate by its UUID", () ->
|
||||
httpDelete(asGlobalAgent(), "/api/hs/office/sepamandates/&{SEPA-Mandate: %{bankAccountIBAN}}")
|
||||
.expecting(HttpStatus.NO_CONTENT)
|
||||
);
|
||||
}
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class InvalidateSepaMandateForDebitor extends UseCase<InvalidateSepaMandateForDebitor> {
|
||||
@@ -16,14 +17,14 @@ public class InvalidateSepaMandateForDebitor extends UseCase<InvalidateSepaManda
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("SEPA-Mandate: %{bankAccountIBAN}", () ->
|
||||
httpGet("/api/hs/office/sepamandates?iban=&{bankAccountIBAN}")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/sepamandates?iban=&{bankAccountIBAN}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"With production data, the bank-account could be used in multiple SEPA-mandates, make sure to use the right one!"
|
||||
);
|
||||
|
||||
return withTitle("Patch the End of the Mandate into the SEPA-Mandate", () ->
|
||||
httpPatch("/api/hs/office/sepamandates/&{SEPA-Mandate: %{bankAccountIBAN}}", usingJsonBody("""
|
||||
httpPatch(asGlobalAgent(), "/api/hs/office/sepamandates/&{SEPA-Mandate: %{bankAccountIBAN}}", usingJsonBody("""
|
||||
{
|
||||
"validTo": ${mandateValidTo}
|
||||
}
|
||||
|
||||
+4
-3
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class CancelMembership extends UseCase<CancelMembership> {
|
||||
@@ -18,12 +19,12 @@ public class CancelMembership extends UseCase<CancelMembership> {
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Membership: %{memberNumber}", () ->
|
||||
httpGet("/api/hs/office/memberships/%{memberNumber}"),
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/memberships/%{memberNumber}"),
|
||||
response -> response.getFromBody("uuid")
|
||||
);
|
||||
|
||||
return withTitle("Patch the New Status Into the Membership", () ->
|
||||
httpPatch("/api/hs/office/memberships/%{Membership: %{memberNumber}}", usingJsonBody("""
|
||||
httpPatch(asGlobalAgent(), "/api/hs/office/memberships/%{Membership: %{memberNumber}}", usingJsonBody("""
|
||||
{
|
||||
"validTo": ${validTo},
|
||||
"status": ${newStatus}
|
||||
@@ -37,7 +38,7 @@ public class CancelMembership extends UseCase<CancelMembership> {
|
||||
protected void verify(final UseCase<CancelMembership>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify That the Membership Got Cancelled",
|
||||
() -> httpGet("/api/hs/office/memberships/%{Membership: %{memberNumber}}")
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/memberships/%{Membership: %{memberNumber}}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
path("validTo").contains("%{validTo}"),
|
||||
path("status").contains("CANCELLED")
|
||||
|
||||
+4
-3
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class CreateMembership extends UseCase<CreateMembership> {
|
||||
@@ -18,13 +19,13 @@ public class CreateMembership extends UseCase<CreateMembership> {
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Partner: %{partnerName}", () ->
|
||||
httpGet("/api/hs/office/partners?name=&{partnerName}")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/partners?name=&{partnerName}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/memberships", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/memberships", usingJsonBody("""
|
||||
{
|
||||
"partner.uuid": ${Partner: %{partnerName}},
|
||||
"memberNumberSuffix": ${%{memberNumberSuffix???}???00},
|
||||
@@ -40,7 +41,7 @@ public class CreateMembership extends UseCase<CreateMembership> {
|
||||
protected void verify(final UseCase<CreateMembership>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify That the Membership Got Created",
|
||||
() -> httpGet("/api/hs/office/memberships/" + response.getLocationUuid())
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/memberships/" + response.getLocationUuid())
|
||||
.expecting(OK).expecting(JSON),
|
||||
path("validFrom").contains("%{validFrom}"),
|
||||
path("status").contains("ACTIVE")
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@ import org.springframework.http.HttpStatus;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.resolveTyped;
|
||||
|
||||
public class CreateCoopAssetsRevertTransferTransaction extends CreateCoopAssetsTransaction {
|
||||
@@ -41,7 +42,7 @@ public class CreateCoopAssetsRevertTransferTransaction extends CreateCoopAssetsT
|
||||
given("negativeAssetValue", resolveTyped("%{transferredValue}", BigDecimal.class).negate());
|
||||
|
||||
verify("Verify Reverted Coop-Assets TRANSFER-Transaction",
|
||||
() -> httpGet("/api/hs/office/coopassetstransactions/" + revertedAssetTxUuid)
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/coopassetstransactions/" + revertedAssetTxUuid)
|
||||
.expecting(HttpStatus.OK).expecting(ContentType.JSON),
|
||||
path("assetValue").contains("%{negativeAssetValue}"),
|
||||
path("comment").contains("%{comment}"),
|
||||
@@ -51,7 +52,7 @@ public class CreateCoopAssetsRevertTransferTransaction extends CreateCoopAssetsT
|
||||
final var adoptionAssetTxUuid = response.getFromBody("revertedAssetTx.['adoptionAssetTx.uuid']");
|
||||
|
||||
verify("Verify Related Coop-Assets ADOPTION-Transaction Also Got Reverted",
|
||||
() -> httpGet("/api/hs/office/coopassetstransactions/" + adoptionAssetTxUuid)
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/coopassetstransactions/" + adoptionAssetTxUuid)
|
||||
.expecting(HttpStatus.OK).expecting(ContentType.JSON),
|
||||
path("reversalAssetTx.['transferAssetTx.uuid']").contains(revertedAssetTxUuid.toString())
|
||||
);
|
||||
|
||||
+4
-3
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public abstract class CreateCoopAssetsTransaction extends UseCase<CreateCoopAssetsTransaction> {
|
||||
@@ -18,13 +19,13 @@ public abstract class CreateCoopAssetsTransaction extends UseCase<CreateCoopAsse
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("#{Find }membershipUuid", () ->
|
||||
httpGet("/api/hs/office/memberships/%{memberNumber}")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/memberships/%{memberNumber}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.getFromBody("uuid")
|
||||
);
|
||||
|
||||
return withTitle("Create the Coop-Assets-%{transactionType} Transaction", () ->
|
||||
httpPost("/api/hs/office/coopassetstransactions", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/coopassetstransactions", usingJsonBody("""
|
||||
{
|
||||
"membership.uuid": ${membershipUuid},
|
||||
"transactionType": ${transactionType},
|
||||
@@ -43,7 +44,7 @@ public abstract class CreateCoopAssetsTransaction extends UseCase<CreateCoopAsse
|
||||
@Override
|
||||
protected void verify(final HttpResponse response) {
|
||||
verify("Verify Coop-Assets %{transactionType}-Transaction",
|
||||
() -> httpGet("/api/hs/office/coopassetstransactions/" + response.getLocationUuid())
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/coopassetstransactions/" + response.getLocationUuid())
|
||||
.expecting(HttpStatus.OK).expecting(ContentType.JSON),
|
||||
path("transactionType").contains("%{transactionType}"),
|
||||
path("assetValue").contains("%{assetValue}"),
|
||||
|
||||
+4
-3
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public abstract class CreateCoopSharesTransaction extends UseCase<CreateCoopSharesTransaction> {
|
||||
@@ -18,13 +19,13 @@ public abstract class CreateCoopSharesTransaction extends UseCase<CreateCoopShar
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("#{Find }membershipUuid", () ->
|
||||
httpGet("/api/hs/office/memberships/%{memberNumber}")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/memberships/%{memberNumber}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.getFromBody("uuid")
|
||||
);
|
||||
|
||||
return withTitle("Create the Coop-Shares-%{transactionType} Transaction", () ->
|
||||
httpPost("/api/hs/office/coopsharestransactions", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/coopsharestransactions", usingJsonBody("""
|
||||
{
|
||||
"membership.uuid": ${membershipUuid},
|
||||
"transactionType": ${transactionType},
|
||||
@@ -42,7 +43,7 @@ public abstract class CreateCoopSharesTransaction extends UseCase<CreateCoopShar
|
||||
@Override
|
||||
protected void verify(final HttpResponse response) {
|
||||
verify("Verify Coop-Shares %{transactionType}-Transaction",
|
||||
() -> httpGet("/api/hs/office/coopsharestransactions/" + response.getLocationUuid())
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/coopsharestransactions/" + response.getLocationUuid())
|
||||
.expecting(HttpStatus.OK).expecting(ContentType.JSON),
|
||||
path("transactionType").contains("%{transactionType}"),
|
||||
path("shareCount").contains("%{shareCount}"),
|
||||
|
||||
+6
-5
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -19,14 +20,14 @@ public class AddOperationsContactToPartner extends UseCase<AddOperationsContactT
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: %{partnerPersonTradeName}", () ->
|
||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
obtain("Person: %{operationsContactGivenName} %{operationsContactFamilyName}", () ->
|
||||
httpPost("/api/hs/office/persons", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/persons", usingJsonBody("""
|
||||
{
|
||||
"personType": "NATURAL_PERSON",
|
||||
"familyName": ${operationsContactFamilyName},
|
||||
@@ -39,7 +40,7 @@ public class AddOperationsContactToPartner extends UseCase<AddOperationsContactT
|
||||
);
|
||||
|
||||
obtain("Contact: %{operationsContactGivenName} %{operationsContactFamilyName}", () ->
|
||||
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/contacts", usingJsonBody("""
|
||||
{
|
||||
"caption": "%{operationsContactGivenName} %{operationsContactFamilyName}",
|
||||
"phoneNumbers": {
|
||||
@@ -54,7 +55,7 @@ public class AddOperationsContactToPartner extends UseCase<AddOperationsContactT
|
||||
"Please check first if that contact already exists, if so, use it's UUID below."
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/relations", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/relations", usingJsonBody("""
|
||||
{
|
||||
"type": "OPERATIONS",
|
||||
"anchor.uuid": ${Person: %{partnerPersonTradeName}},
|
||||
@@ -69,7 +70,7 @@ public class AddOperationsContactToPartner extends UseCase<AddOperationsContactT
|
||||
protected void verify(final UseCase<AddOperationsContactToPartner>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify the New OPERATIONS Relation",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=OPERATIONS&personData=" + uriEncoded(
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=OPERATIONS&personData=" + uriEncoded(
|
||||
"%{operationsContactFamilyName}"))
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].contact.caption").contains("%{operationsContactGivenName} %{operationsContactFamilyName}")
|
||||
|
||||
+6
-5
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -19,14 +20,14 @@ public class AddRepresentativeToPartner extends UseCase<AddRepresentativeToPartn
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: %{partnerPersonTradeName}", () ->
|
||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
obtain("Person: %{representativeGivenName} %{representativeFamilyName}", () ->
|
||||
httpPost("/api/hs/office/persons", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/persons", usingJsonBody("""
|
||||
{
|
||||
"personType": "NATURAL_PERSON",
|
||||
"familyName": ${representativeFamilyName},
|
||||
@@ -39,7 +40,7 @@ public class AddRepresentativeToPartner extends UseCase<AddRepresentativeToPartn
|
||||
);
|
||||
|
||||
obtain("Contact: %{representativeGivenName} %{representativeFamilyName}", () ->
|
||||
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/contacts", usingJsonBody("""
|
||||
{
|
||||
"caption": "%{representativeGivenName} %{representativeFamilyName}",
|
||||
"postalAddress": {
|
||||
@@ -57,7 +58,7 @@ public class AddRepresentativeToPartner extends UseCase<AddRepresentativeToPartn
|
||||
"Please check first if that contact already exists, if so, use it's UUID below."
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/relations", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/relations", usingJsonBody("""
|
||||
{
|
||||
"type": "REPRESENTATIVE",
|
||||
"anchor.uuid": ${Person: %{partnerPersonTradeName}},
|
||||
@@ -72,7 +73,7 @@ public class AddRepresentativeToPartner extends UseCase<AddRepresentativeToPartn
|
||||
protected void verify(final UseCase<AddRepresentativeToPartner>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify the REPRESENTATIVE Relation Got Removed",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=REPRESENTATIVE&personData=" + uriEncoded("%{representativeFamilyName}"))
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=REPRESENTATIVE&personData=" + uriEncoded("%{representativeFamilyName}"))
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].contact.caption").contains("%{representativeGivenName} %{representativeFamilyName}")
|
||||
);
|
||||
|
||||
+6
-5
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class CreatePartner extends UseCase<CreatePartner> {
|
||||
@@ -24,14 +25,14 @@ public class CreatePartner extends UseCase<CreatePartner> {
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: Hostsharing eG", () ->
|
||||
httpGet("/api/hs/office/persons?name=Hostsharing+eG")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/persons?name=Hostsharing+eG")
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"Even in production data we expect this query to return just a single result." // TODO.impl: add constraint?
|
||||
);
|
||||
|
||||
obtain("Person: %{%{tradeName???}???%{givenName???} %{familyName???}}", () ->
|
||||
httpPost("/api/hs/office/persons", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/persons", usingJsonBody("""
|
||||
{
|
||||
"personType": ${personType???},
|
||||
"tradeName": ${tradeName???},
|
||||
@@ -43,7 +44,7 @@ public class CreatePartner extends UseCase<CreatePartner> {
|
||||
);
|
||||
|
||||
obtain("Contact: %{contactCaption}", () ->
|
||||
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/contacts", usingJsonBody("""
|
||||
{
|
||||
"caption": ${contactCaption},
|
||||
"postalAddress": {
|
||||
@@ -60,7 +61,7 @@ public class CreatePartner extends UseCase<CreatePartner> {
|
||||
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/partners", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/partners", usingJsonBody("""
|
||||
{
|
||||
"partnerNumber": ${partnerNumber},
|
||||
"partnerRel": {
|
||||
@@ -84,7 +85,7 @@ public class CreatePartner extends UseCase<CreatePartner> {
|
||||
protected void verify(final UseCase<CreatePartner>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify the New Partner Relation",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&contactData=&{contactCaption}")
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=PARTNER&contactData=&{contactCaption}")
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1)
|
||||
);
|
||||
}
|
||||
|
||||
+4
-3
@@ -4,6 +4,8 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
|
||||
public class DeletePartner extends UseCase<DeletePartner> {
|
||||
|
||||
public DeletePartner(final ScenarioTest testSuite) {
|
||||
@@ -18,10 +20,9 @@ public class DeletePartner extends UseCase<DeletePartner> {
|
||||
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
withTitle("Delete Partner by its UUID", () ->
|
||||
httpDelete("/api/hs/office/partners/&{Partner: Delete AG}")
|
||||
return withTitle("Delete Partner by its UUID", () ->
|
||||
httpDelete(asGlobalAgent(), "/api/hs/office/partners/&{Partner: Delete AG}")
|
||||
.expecting(HttpStatus.NO_CONTENT)
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-9
@@ -1,10 +1,12 @@
|
||||
package net.hostsharing.hsadminng.hs.office.scenarios.partner;
|
||||
|
||||
import lombok.val;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -18,7 +20,7 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Partner: %{partnerNumber}",
|
||||
() -> httpGet("/api/hs/office/partners/%{partnerNumber}")
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/partners/%{partnerNumber}")
|
||||
.reportWithResponse().expecting(OK).expecting(JSON),
|
||||
response -> response.getFromBody("uuid"),
|
||||
"Even in production data we expect this query to return just a single result."
|
||||
@@ -30,8 +32,8 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
"partnerRel.holder.uuid",
|
||||
"Person: %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}");
|
||||
|
||||
withTitle("New Partner-Person+Contact: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}",
|
||||
() -> httpPatch("/api/hs/office/partners/%{Partner: %{partnerNumber}}",
|
||||
val result = withTitle("New Partner-Person+Contact: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}",
|
||||
() -> httpPatch(asGlobalAgent(), "/api/hs/office/partners/%{Partner: %{partnerNumber}}",
|
||||
usingJsonBody("""
|
||||
{
|
||||
"partnerRel": {
|
||||
@@ -68,7 +70,7 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
|
||||
obtain(
|
||||
"Representative-Relation: %{representativeGivenName} %{representativeFamilyName} for Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}",
|
||||
() -> httpPost("/api/hs/office/relations",
|
||||
() -> httpPost(asGlobalAgent(), "/api/hs/office/relations",
|
||||
usingJsonBody("""
|
||||
{
|
||||
"type": "REPRESENTATIVE",
|
||||
@@ -88,14 +90,14 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
// outro: die Erbengemeinschaft hat eine Frist von 6 Monaten, um die Mitgliedschaft einer Person zu übertragen
|
||||
// →nächster "Drecksfall"
|
||||
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verify(final UseCase<ReplaceDeceasedPartnerWithCommunityOfHeirs>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify the Updated Partner",
|
||||
() -> httpGet("/api/hs/office/partners/%{partnerNumber}")
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/partners/%{partnerNumber}")
|
||||
.expecting(OK).expecting(JSON).expectObject(),
|
||||
path("partnerRel.holder.tradeName").contains(
|
||||
"Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"),
|
||||
@@ -106,7 +108,7 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
|
||||
verify(
|
||||
"Verify the Ex-Partner-Relation",
|
||||
() -> httpGet(
|
||||
() -> httpGet(asGlobalAgent(),
|
||||
"/api/hs/office/relations?relationType=EX_PARTNER&personUuid=%{Person: %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}}")
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].anchor.tradeName").contains(
|
||||
@@ -115,7 +117,7 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
|
||||
verify(
|
||||
"Verify the Representative-Relation",
|
||||
() -> httpGet(
|
||||
() -> httpGet(asGlobalAgent(),
|
||||
"/api/hs/office/relations?relationType=REPRESENTATIVE&personUuid=%{Person: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}}")
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].anchor.tradeName").contains(
|
||||
@@ -128,7 +130,7 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
|
||||
verify(
|
||||
"Verify the Debitor-Relation",
|
||||
() -> httpGet(
|
||||
() -> httpGet(asGlobalAgent(),
|
||||
"/api/hs/office/debitors?partnerNumber=%{partnerNumber}")
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].debitorRel.anchor.tradeName").contains(
|
||||
|
||||
+3
-1
@@ -5,6 +5,8 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
|
||||
public class CreatePerson extends UseCase<CreatePerson> {
|
||||
|
||||
public CreatePerson(final ScenarioTest testSuite, final String resultAlias) {
|
||||
@@ -15,7 +17,7 @@ public class CreatePerson extends UseCase<CreatePerson> {
|
||||
protected HttpResponse run() {
|
||||
|
||||
return withTitle("Create the Person", () ->
|
||||
httpPost("/api/hs/office/persons", usingJsonBody("""
|
||||
httpPost(asGlobalAgent(), "/api/hs/office/persons", usingJsonBody("""
|
||||
{
|
||||
"personType": ${personType},
|
||||
"tradeName": ${tradeName}
|
||||
|
||||
+6
-6
@@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class ShouldUpdatePersonData extends UseCase<ShouldUpdatePersonData> {
|
||||
@@ -18,29 +19,28 @@ public class ShouldUpdatePersonData extends UseCase<ShouldUpdatePersonData> {
|
||||
|
||||
obtain(
|
||||
"personUuid",
|
||||
() -> httpGet("/api/hs/office/persons?name=" + uriEncoded("%{oldFamilyName}"))
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/persons?name=" + uriEncoded("%{oldFamilyName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
withTitle("Patch the Additional Phone-Number into the Person", () ->
|
||||
httpPatch("/api/hs/office/persons/%{personUuid}", usingJsonBody("""
|
||||
return withTitle("Patch the Additional Phone-Number into the Person", () ->
|
||||
httpPatch(
|
||||
asGlobalAgent(), "/api/hs/office/persons/%{personUuid}", usingJsonBody("""
|
||||
{
|
||||
"familyName": ${newFamilyName}
|
||||
}
|
||||
"""))
|
||||
.expecting(HttpStatus.OK)
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verify(final UseCase<ShouldUpdatePersonData>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify that the Family Name Got Amended",
|
||||
() -> httpGet("/api/hs/office/persons/%{personUuid}")
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/persons/%{personUuid}")
|
||||
.expecting(OK).expecting(JSON),
|
||||
path("familyName").contains("%{newFamilyName}")
|
||||
);
|
||||
|
||||
+4
-3
@@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
|
||||
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
@@ -19,7 +20,7 @@ public class RemoveOperationsContactFromPartner extends UseCase<RemoveOperations
|
||||
|
||||
obtain("Operations-Contact: %{operationsContactPerson}",
|
||||
() ->
|
||||
httpGet("/api/hs/office/relations?relationType=OPERATIONS&name=" + uriEncoded(
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=OPERATIONS&name=" + uriEncoded(
|
||||
"%{operationsContactPerson}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
@@ -27,7 +28,7 @@ public class RemoveOperationsContactFromPartner extends UseCase<RemoveOperations
|
||||
);
|
||||
|
||||
return withTitle("Delete the Contact", () ->
|
||||
httpDelete("/api/hs/office/relations/&{Operations-Contact: %{operationsContactPerson}}")
|
||||
httpDelete(asGlobalAgent(), "/api/hs/office/relations/&{Operations-Contact: %{operationsContactPerson}}")
|
||||
.expecting(NO_CONTENT)
|
||||
);
|
||||
}
|
||||
@@ -36,7 +37,7 @@ public class RemoveOperationsContactFromPartner extends UseCase<RemoveOperations
|
||||
protected void verify(final UseCase<RemoveOperationsContactFromPartner>.HttpResponse response) {
|
||||
verify(
|
||||
"Verify the New OPERATIONS Relation",
|
||||
() -> httpGet("/api/hs/office/relations/&{Operations-Contact: %{operationsContactPerson}}")
|
||||
() -> httpGet(asGlobalAgent(), "/api/hs/office/relations/&{Operations-Contact: %{operationsContactPerson}}")
|
||||
.expecting(NOT_FOUND)
|
||||
);
|
||||
}
|
||||
|
||||
+5
-4
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -19,7 +20,7 @@ public class SubscribeExistingPersonAndContactToMailinglist extends UseCase<Subs
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: %{partnerPersonTradeName}", () ->
|
||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
@@ -27,20 +28,20 @@ public class SubscribeExistingPersonAndContactToMailinglist extends UseCase<Subs
|
||||
|
||||
obtain(
|
||||
"Person: %{subscriberGivenName} %{subscriberFamilyName}", () ->
|
||||
httpGet("/api/hs/office/persons?name=%{subscriberFamilyName}")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/persons?name=%{subscriberFamilyName}")
|
||||
.expecting(HttpStatus.OK).expecting(ContentType.JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In real scenarios there are most likely multiple results and you have to choose the right one."
|
||||
);
|
||||
|
||||
obtain("Contact: %{subscriberEMailAddress}", () ->
|
||||
httpGet("/api/hs/office/contacts?emailAddress=%{subscriberEMailAddress}")
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/contacts?emailAddress=%{subscriberEMailAddress}")
|
||||
.expecting(HttpStatus.OK).expecting(ContentType.JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In real scenarios there are most likely multiple results and you have to choose the right one."
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/relations", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/relations", usingJsonBody("""
|
||||
{
|
||||
"type": "SUBSCRIBER",
|
||||
"mark": ${mailingList},
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -17,13 +18,13 @@ public class SubscribeNewPersonAndContactToMailinglist extends UseCase<Subscribe
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: %{partnerPersonTradeName}", () ->
|
||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/relations", usingJsonBody("""
|
||||
return httpPost(asGlobalAgent(), "/api/hs/office/relations", usingJsonBody("""
|
||||
{
|
||||
"type": "SUBSCRIBER",
|
||||
"mark": ${mailingList},
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.FakeLoginUser.asGlobalAgent;
|
||||
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
@@ -17,7 +18,7 @@ public class UnsubscribeFromMailinglist extends UseCase<UnsubscribeFromMailingli
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Subscription: %{subscriberEMailAddress}", () ->
|
||||
httpGet("/api/hs/office/relations?relationType=SUBSCRIBER" +
|
||||
httpGet(asGlobalAgent(), "/api/hs/office/relations?relationType=SUBSCRIBER" +
|
||||
"&mark=" + uriEncoded("%{mailingList}") +
|
||||
"&contactData=" + uriEncoded("%{subscriberEMailAddress}"))
|
||||
.expecting(OK).expecting(JSON),
|
||||
@@ -26,7 +27,7 @@ public class UnsubscribeFromMailinglist extends UseCase<UnsubscribeFromMailingli
|
||||
);
|
||||
|
||||
return withTitle("Delete the Subscriber-Relation by its UUID", () ->
|
||||
httpDelete("/api/hs/office/relations/&{Subscription: %{subscriberEMailAddress}}")
|
||||
httpDelete(asGlobalAgent(), "/api/hs/office/relations/&{Subscription: %{subscriberEMailAddress}}")
|
||||
.expecting(NO_CONTENT)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.hostsharing.hsadminng.hs.scenarios;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.hostsharing.hsadminng.config.JwtFakeBearer;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class FakeLoginUser {
|
||||
|
||||
final static String GLOBAL_AGENT = "superuser-alex@hostsharing.net"; // TODO.test: use global:AGENT when implemented
|
||||
|
||||
private String name;
|
||||
|
||||
public static FakeLoginUser as(final String name) {
|
||||
return new FakeLoginUser(name);
|
||||
}
|
||||
|
||||
public static FakeLoginUser asGlobalAgent() {
|
||||
return new FakeLoginUser(GLOBAL_AGENT);
|
||||
}
|
||||
|
||||
public String bearer() {
|
||||
return JwtFakeBearer.bearer(name);
|
||||
}
|
||||
}
|
||||
@@ -9,5 +9,5 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
@Target(METHOD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface Requires {
|
||||
String value();
|
||||
String[] value();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -62,8 +64,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ExtendWith(IgnoreOnFailureExtension.class)
|
||||
public abstract class ScenarioTest extends ContextBasedTest {
|
||||
|
||||
final static String RUN_AS_USER = "superuser-alex@hostsharing.net"; // TODO.test: use global:AGENT when implemented
|
||||
|
||||
private final Stack<String> currentTestMethodProduces = new Stack<>();
|
||||
|
||||
protected ScenarioTest scenarioTest = this;
|
||||
@@ -116,20 +116,17 @@ public abstract class ScenarioTest extends ContextBasedTest {
|
||||
|
||||
@SneakyThrows
|
||||
private void callRequiredProducers(final Method currentTestMethod) {
|
||||
final var testMethodRequires = Optional.of(currentTestMethod)
|
||||
final var testMethodRequires = Stream.of(currentTestMethod)
|
||||
.map(m -> m.getAnnotation(Requires.class))
|
||||
.map(Requires::value)
|
||||
.orElse(null);
|
||||
if (testMethodRequires != null) {
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(annotation -> Stream.of(annotation.value()))
|
||||
.collect(Collectors.toSet());
|
||||
if (!testMethodRequires.isEmpty()) {
|
||||
for (Method potentialProducerMethod : getPotentialProducerMethods()) {
|
||||
final var producesAnnot = potentialProducerMethod.getAnnotation(Produces.class);
|
||||
final var testMethodProduces = producedAliases(producesAnnot);
|
||||
// @formatter:off
|
||||
if ( // that method can produce something required
|
||||
testMethodProduces.contains(testMethodRequires) &&
|
||||
|
||||
// and it does not produce anything we already have (would cause errors)
|
||||
SetUtils.intersection(testMethodProduces, knowVariables().keySet()).isEmpty()
|
||||
if ( thatMethodProducesSomethingRequired(testMethodProduces, testMethodRequires) &&
|
||||
thatMethodDoesNotProduceAnythingWeAlreadyHave(testMethodProduces)
|
||||
) {
|
||||
assertThat(producesAnnot.permanent()).as("cannot depend on non-permanent producer: " + potentialProducerMethod);
|
||||
|
||||
@@ -140,15 +137,30 @@ public abstract class ScenarioTest extends ContextBasedTest {
|
||||
// and finally we call the producer method
|
||||
invokeProducerMethod(this, potentialProducerMethod);
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
assertThat(knowVariables().containsKey(testMethodRequires))
|
||||
assertThat(haveIntersection(knowVariables().keySet(), testMethodRequires))
|
||||
.as("no @Producer for @Required(\"" + testMethodRequires + "\") found")
|
||||
.isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean haveIntersection(final Set<String> set1, final Set<String> set2) {
|
||||
return !SetUtils.intersection(set1, set2).isEmpty();
|
||||
}
|
||||
|
||||
private static boolean areDisjunct(final Set<String> set1, final Set<String> set2) {
|
||||
return !haveIntersection(set1, set2);
|
||||
}
|
||||
|
||||
private static boolean thatMethodProducesSomethingRequired(final Set<String> testMethodProduces, final Set<String> testMethodRequires) {
|
||||
return haveIntersection(testMethodProduces, testMethodRequires);
|
||||
}
|
||||
|
||||
private static boolean thatMethodDoesNotProduceAnythingWeAlreadyHave(final Set<String> testMethodProduces) {
|
||||
return areDisjunct(testMethodProduces, knowVariables().keySet());
|
||||
}
|
||||
|
||||
private void keepProducesAlias(final Method currentTestMethod) {
|
||||
final var producesAnnot = currentTestMethod.getAnnotation(Produces.class);
|
||||
if (producesAnnot != null) {
|
||||
|
||||
@@ -37,7 +37,6 @@ import static java.net.URLEncoder.encode;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.TemplateResolver.Resolver.DROP_COMMENTS;
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.TemplateResolver.Resolver.KEEP_COMMENTS;
|
||||
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
|
||||
import static net.hostsharing.hsadminng.test.DebuggerDetection.isDebuggerAttached;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
@@ -76,7 +75,7 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
requirements.put(alias, useCaseFactory);
|
||||
}
|
||||
|
||||
public final HttpResponse doRun() {
|
||||
public final HttpResponse thenExpect(final HttpStatus expectedStatus) {
|
||||
if (introduction != null) {
|
||||
testReport.printPara(introduction);
|
||||
}
|
||||
@@ -95,8 +94,11 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
}
|
||||
})
|
||||
);
|
||||
final var response = run();
|
||||
final var response = run(expectedStatus);
|
||||
assertThat(response).as("use case implementation must return main response, never null").isNotNull();
|
||||
if (!response.status.isError()) {
|
||||
verify(response);
|
||||
}
|
||||
keepInProduceAlias(response);
|
||||
|
||||
resetProperties();
|
||||
@@ -104,7 +106,14 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
return response;
|
||||
}
|
||||
|
||||
protected abstract HttpResponse run();
|
||||
// this method is called by the test framework, override, but do not call from subclass
|
||||
protected HttpResponse run(final HttpStatus expectedStatus) {
|
||||
assertThat(expectedStatus).as("legacy signature only defined for HttpStatus.OK").isEqualTo(HttpStatus.OK);
|
||||
return run();
|
||||
};
|
||||
|
||||
// legacy signature for backwards compatibility, only called by above method
|
||||
protected HttpResponse run() {return null;}
|
||||
|
||||
protected void verify(final HttpResponse response) {
|
||||
}
|
||||
@@ -171,20 +180,22 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpGet(final String uriPathWithPlaceholders) {
|
||||
public final HttpResponse httpGet(final FakeLoginUser loginUser, final String uriPathWithPlaceholders) {
|
||||
return httpGet(uriPathWithPlaceholders,
|
||||
req -> req.header("Authorization", bearer(ScenarioTest.RUN_AS_USER)));
|
||||
req -> req.header("Authorization", loginUser.bearer()));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpPost(final String uriPathWithPlaceholders, final JsonTemplate bodyJsonTemplate) {
|
||||
public final HttpResponse httpPost(
|
||||
final FakeLoginUser loginUser, final String uriPathWithPlaceholders,
|
||||
final JsonTemplate bodyJsonTemplate) {
|
||||
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders, DROP_COMMENTS);
|
||||
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.POST(BodyPublishers.ofString(requestBody))
|
||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Authorization", bearer(ScenarioTest.RUN_AS_USER))
|
||||
.header("Authorization", loginUser.bearer())
|
||||
.timeout(seconds(HTTP_TIMEOUT_SECONDS))
|
||||
.build();
|
||||
final var response = client.send(request, BodyHandlers.ofString());
|
||||
@@ -192,14 +203,17 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpPatch(final String uriPathWithPlaceholders, final JsonTemplate bodyJsonTemplate) {
|
||||
public final HttpResponse httpPatch(
|
||||
final FakeLoginUser loginUser, final String uriPathWithPlaceholders,
|
||||
final JsonTemplate bodyJsonTemplate
|
||||
) {
|
||||
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders, DROP_COMMENTS);
|
||||
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.method(HttpMethod.PATCH.toString(), BodyPublishers.ofString(requestBody))
|
||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Authorization", bearer(ScenarioTest.RUN_AS_USER))
|
||||
.header("Authorization", loginUser.bearer())
|
||||
.timeout(seconds(HTTP_TIMEOUT_SECONDS))
|
||||
.build();
|
||||
final var response = client.send(request, BodyHandlers.ofString());
|
||||
@@ -207,13 +221,13 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpDelete(final String uriPathWithPlaceholders) {
|
||||
public final HttpResponse httpDelete(final FakeLoginUser loginUser, final String uriPathWithPlaceholders) {
|
||||
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders, DROP_COMMENTS);
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.DELETE()
|
||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Authorization", bearer(ScenarioTest.RUN_AS_USER))
|
||||
.header("Authorization", loginUser.bearer())
|
||||
.timeout(seconds(HTTP_TIMEOUT_SECONDS))
|
||||
.build();
|
||||
final var response = client.send(request, BodyHandlers.ofString());
|
||||
|
||||
Reference in New Issue
Block a user