add API validation
This commit is contained in:
parent
4f22dffe5d
commit
67e850f9b2
@ -55,6 +55,7 @@ dependencies {
|
|||||||
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
|
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
|
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||||
implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.8.1'
|
implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.8.1'
|
||||||
implementation 'org.springdoc:springdoc-openapi-ui:1.6.11'
|
implementation 'org.springdoc:springdoc-openapi-ui:1.6.11'
|
||||||
implementation 'org.liquibase:liquibase-core'
|
implementation 'org.liquibase:liquibase-core'
|
||||||
@ -106,7 +107,7 @@ tasks.named('test') {
|
|||||||
openapiProcessor {
|
openapiProcessor {
|
||||||
springRoot {
|
springRoot {
|
||||||
processorName 'spring'
|
processorName 'spring'
|
||||||
processor 'io.openapiprocessor:openapi-processor-spring:2022.4'
|
processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
|
||||||
apiPath "$projectDir/src/main/resources/api-definition.yaml"
|
apiPath "$projectDir/src/main/resources/api-definition.yaml"
|
||||||
mapping "$projectDir/src/main/resources/api-mappings.yaml"
|
mapping "$projectDir/src/main/resources/api-mappings.yaml"
|
||||||
targetDir "$projectDir/build/generated/sources/openapi"
|
targetDir "$projectDir/build/generated/sources/openapi"
|
||||||
@ -115,7 +116,7 @@ openapiProcessor {
|
|||||||
}
|
}
|
||||||
springRbac {
|
springRbac {
|
||||||
processorName 'spring'
|
processorName 'spring'
|
||||||
processor 'io.openapiprocessor:openapi-processor-spring:2022.4'
|
processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
|
||||||
apiPath "$projectDir/src/main/resources/api-definition/rbac/rbac.yaml"
|
apiPath "$projectDir/src/main/resources/api-definition/rbac/rbac.yaml"
|
||||||
mapping "$projectDir/src/main/resources/api-definition/rbac/api-mappings.yaml"
|
mapping "$projectDir/src/main/resources/api-definition/rbac/api-mappings.yaml"
|
||||||
targetDir "$projectDir/build/generated/sources/openapi"
|
targetDir "$projectDir/build/generated/sources/openapi"
|
||||||
@ -124,7 +125,7 @@ openapiProcessor {
|
|||||||
}
|
}
|
||||||
springTest {
|
springTest {
|
||||||
processorName 'spring'
|
processorName 'spring'
|
||||||
processor 'io.openapiprocessor:openapi-processor-spring:2022.4'
|
processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
|
||||||
apiPath "$projectDir/src/main/resources/api-definition/test/test.yaml"
|
apiPath "$projectDir/src/main/resources/api-definition/test/test.yaml"
|
||||||
mapping "$projectDir/src/main/resources/api-definition/test/api-mappings.yaml"
|
mapping "$projectDir/src/main/resources/api-definition/test/api-mappings.yaml"
|
||||||
targetDir "$projectDir/build/generated/sources/openapi"
|
targetDir "$projectDir/build/generated/sources/openapi"
|
||||||
@ -133,7 +134,7 @@ openapiProcessor {
|
|||||||
}
|
}
|
||||||
springHs {
|
springHs {
|
||||||
processorName 'spring'
|
processorName 'spring'
|
||||||
processor 'io.openapiprocessor:openapi-processor-spring:2022.4'
|
processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
|
||||||
apiPath "$projectDir/src/main/resources/api-definition/hs-office/hs-office.yaml"
|
apiPath "$projectDir/src/main/resources/api-definition/hs-office/hs-office.yaml"
|
||||||
mapping "$projectDir/src/main/resources/api-definition/hs-office/api-mappings.yaml"
|
mapping "$projectDir/src/main/resources/api-definition/hs-office/api-mappings.yaml"
|
||||||
targetDir "$projectDir/build/generated/sources/openapi"
|
targetDir "$projectDir/build/generated/sources/openapi"
|
||||||
|
@ -5,10 +5,12 @@ import lombok.Getter;
|
|||||||
import org.iban4j.Iban4jException;
|
import org.iban4j.Iban4jException;
|
||||||
import org.springframework.core.NestedExceptionUtils;
|
import org.springframework.core.NestedExceptionUtils;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
|
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
|
||||||
import org.springframework.orm.jpa.JpaSystemException;
|
import org.springframework.orm.jpa.JpaSystemException;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.context.request.WebRequest;
|
import org.springframework.web.context.request.WebRequest;
|
||||||
@ -65,21 +67,38 @@ public class RestResponseEntityExceptionHandler
|
|||||||
@ExceptionHandler(Throwable.class)
|
@ExceptionHandler(Throwable.class)
|
||||||
protected ResponseEntity<CustomErrorResponse> handleOtherExceptions(
|
protected ResponseEntity<CustomErrorResponse> handleOtherExceptions(
|
||||||
final Throwable exc, final WebRequest request) {
|
final Throwable exc, final WebRequest request) {
|
||||||
final var message = firstLine(NestedExceptionUtils.getMostSpecificCause(exc).getMessage());
|
final var message = firstMessageLine(NestedExceptionUtils.getMostSpecificCause(exc));
|
||||||
return errorResponse(request, httpStatus(message).orElse(HttpStatus.INTERNAL_SERVER_ERROR), message);
|
return errorResponse(request, httpStatus(message).orElse(HttpStatus.INTERNAL_SERVER_ERROR), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked,rawtypes")
|
||||||
|
protected ResponseEntity handleMethodArgumentNotValid(
|
||||||
|
MethodArgumentNotValidException exc,
|
||||||
|
HttpHeaders headers,
|
||||||
|
HttpStatus status,
|
||||||
|
WebRequest request) {
|
||||||
|
final var errorList = exc
|
||||||
|
.getBindingResult()
|
||||||
|
.getFieldErrors()
|
||||||
|
.stream()
|
||||||
|
.map(fieldError -> fieldError.getField() + " " + fieldError.getDefaultMessage() + " but is \""
|
||||||
|
+ fieldError.getRejectedValue() + "\"")
|
||||||
|
.toList();
|
||||||
|
return errorResponse(request, HttpStatus.BAD_REQUEST, errorList.toString());
|
||||||
|
}
|
||||||
|
|
||||||
private String userReadableEntityClassName(final String exceptionMessage) {
|
private String userReadableEntityClassName(final String exceptionMessage) {
|
||||||
final var regex = "(net.hostsharing.hsadminng.[a-z0-9_.]*.[A-Za-z0-9_$]*Entity) ";
|
final var regex = "(net.hostsharing.hsadminng.[a-z0-9_.]*.[A-Za-z0-9_$]*Entity) ";
|
||||||
final var pattern = Pattern.compile(regex);
|
final var pattern = Pattern.compile(regex);
|
||||||
final var matcher = pattern.matcher(exceptionMessage);
|
final var matcher = pattern.matcher(exceptionMessage);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
final var entityName = matcher.group(1);
|
final var entityName = matcher.group(1);
|
||||||
final var entityClass = resolveClassOrNull(entityName);
|
final var entityClass = resolveClass(entityName);
|
||||||
if (entityClass != null) {
|
if (entityClass.isPresent()) {
|
||||||
return (entityClass.isAnnotationPresent(DisplayName.class)
|
return (entityClass.get().isAnnotationPresent(DisplayName.class)
|
||||||
? exceptionMessage.replace(entityName, entityClass.getAnnotation(DisplayName.class).value())
|
? exceptionMessage.replace(entityName, entityClass.get().getAnnotation(DisplayName.class).value())
|
||||||
: exceptionMessage.replace(entityName, entityClass.getSimpleName()))
|
: exceptionMessage.replace(entityName, entityClass.get().getSimpleName()))
|
||||||
.replace(" with id ", " with uuid ");
|
.replace(" with id ", " with uuid ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,11 +106,11 @@ public class RestResponseEntityExceptionHandler
|
|||||||
return exceptionMessage;
|
return exceptionMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Class<?> resolveClassOrNull(final String entityName) {
|
private static Optional<Class<?>> resolveClass(final String entityName) {
|
||||||
try {
|
try {
|
||||||
return ClassLoader.getSystemClassLoader().loadClass(entityName);
|
return Optional.of(ClassLoader.getSystemClassLoader().loadClass(entityName));
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
return null;
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +134,13 @@ public class RestResponseEntityExceptionHandler
|
|||||||
new CustomErrorResponse(request.getContextPath(), httpStatus, message), httpStatus);
|
new CustomErrorResponse(request.getContextPath(), httpStatus, message), httpStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String firstMessageLine(final Throwable exception) {
|
||||||
|
if (exception.getMessage() != null) {
|
||||||
|
return firstLine(exception.getMessage());
|
||||||
|
}
|
||||||
|
return "ERROR: [500] " + exception.getClass().getName();
|
||||||
|
}
|
||||||
|
|
||||||
private String firstLine(final String message) {
|
private String firstLine(final String message) {
|
||||||
return message.split("\\r|\\n|\\r\\n", 0)[0];
|
return message.split("\\r|\\n|\\r\\n", 0)[0];
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
@NonNullApi
|
||||||
|
@NonNullFields
|
||||||
|
package net.hostsharing.hsadminng.errors;
|
||||||
|
|
||||||
|
import org.springframework.lang.NonNullApi;
|
||||||
|
import org.springframework.lang.NonNullFields;
|
@ -19,7 +19,6 @@ import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBui
|
|||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
vatCountryCode:
|
vatCountryCode:
|
||||||
type: string
|
type: string
|
||||||
pattern: '^[A_Z][A-Z]$'
|
pattern: '^[A-Z][A-Z]$'
|
||||||
vatBusiness:
|
vatBusiness:
|
||||||
type: boolean
|
type: boolean
|
||||||
refundBankAccount:
|
refundBankAccount:
|
||||||
@ -40,7 +40,7 @@ components:
|
|||||||
nullable: true
|
nullable: true
|
||||||
vatCountryCode:
|
vatCountryCode:
|
||||||
type: string
|
type: string
|
||||||
pattern: '^[A_Z][A-Z]$'
|
pattern: '^[A-Z][A-Z]$'
|
||||||
nullable: true
|
nullable: true
|
||||||
vatBusiness:
|
vatBusiness:
|
||||||
type: boolean
|
type: boolean
|
||||||
@ -56,9 +56,11 @@ components:
|
|||||||
partnerUuid:
|
partnerUuid:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
nullable: false
|
||||||
billingContactUuid:
|
billingContactUuid:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
nullable: false
|
||||||
debitorNumber:
|
debitorNumber:
|
||||||
type: integer
|
type: integer
|
||||||
format: int32
|
format: int32
|
||||||
@ -68,7 +70,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
vatCountryCode:
|
vatCountryCode:
|
||||||
type: string
|
type: string
|
||||||
pattern: '^[A_Z][A-Z]$'
|
pattern: '^[A-Z][A-Z]$'
|
||||||
vatBusiness:
|
vatBusiness:
|
||||||
type: boolean
|
type: boolean
|
||||||
refundBankAccountUuid:
|
refundBankAccountUuid:
|
||||||
|
@ -15,16 +15,21 @@ components:
|
|||||||
$ref: './hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContact'
|
$ref: './hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContact'
|
||||||
registrationOffice:
|
registrationOffice:
|
||||||
type: string
|
type: string
|
||||||
|
nullable: true
|
||||||
registrationNumber:
|
registrationNumber:
|
||||||
type: string
|
type: string
|
||||||
|
nullable: true
|
||||||
birthName:
|
birthName:
|
||||||
type: string
|
type: string
|
||||||
|
nullable: true
|
||||||
birthday:
|
birthday:
|
||||||
type: string
|
type: string
|
||||||
format: date
|
format: date
|
||||||
|
nullable: true
|
||||||
dateOfDeath:
|
dateOfDeath:
|
||||||
type: string
|
type: string
|
||||||
format: date
|
format: date
|
||||||
|
nullable: true
|
||||||
|
|
||||||
HsOfficePartnerPatch:
|
HsOfficePartnerPatch:
|
||||||
type: object
|
type: object
|
||||||
@ -84,8 +89,3 @@ components:
|
|||||||
required:
|
required:
|
||||||
- personUuid
|
- personUuid
|
||||||
- contactUuid
|
- contactUuid
|
||||||
- registrationOffice
|
|
||||||
- registrationNumber
|
|
||||||
- birthName
|
|
||||||
- birthday
|
|
||||||
- dateOfDeath
|
|
||||||
|
@ -5,16 +5,24 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
|
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
|
||||||
import org.springframework.orm.jpa.JpaSystemException;
|
import org.springframework.orm.jpa.JpaSystemException;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.validation.FieldError;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.context.request.WebRequest;
|
import org.springframework.web.context.request.WebRequest;
|
||||||
|
|
||||||
import javax.persistence.EntityNotFoundException;
|
import javax.persistence.EntityNotFoundException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class RestResponseEntityExceptionHandlerUnitTest {
|
class RestResponseEntityExceptionHandlerUnitTest {
|
||||||
@ -167,6 +175,32 @@ class RestResponseEntityExceptionHandlerUnitTest {
|
|||||||
assertThat(errorResponse.getBody().getMessage()).isEqualTo("given error message");
|
assertThat(errorResponse.getBody().getMessage()).isEqualTo("given error message");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void handleMethodArgumentNotValidException() {
|
||||||
|
// given
|
||||||
|
final var givenBindingResult = mock(BindingResult.class);
|
||||||
|
when(givenBindingResult.getFieldErrors()).thenReturn(List.of(
|
||||||
|
new FieldError("someObject", "someField", "someRejectedValue", false, null, null, "expected to be something")
|
||||||
|
));
|
||||||
|
final var givenException = new MethodArgumentNotValidException(
|
||||||
|
mock(MethodParameter.class),
|
||||||
|
givenBindingResult
|
||||||
|
|
||||||
|
);
|
||||||
|
final var givenWebRequest = mock(WebRequest.class);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var errorResponse = exceptionHandler.handleMethodArgumentNotValid(givenException,
|
||||||
|
HttpHeaders.EMPTY, HttpStatus.BAD_REQUEST, givenWebRequest);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(errorResponse.getStatusCodeValue()).isEqualTo(400);
|
||||||
|
assertThat(errorResponse.getBody())
|
||||||
|
.isInstanceOf(CustomErrorResponse.class)
|
||||||
|
.extracting("message")
|
||||||
|
.isEqualTo("[someField expected to be something but is \"someRejectedValue\"]");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void handleOtherExceptionsWithoutErrorCode() {
|
void handleOtherExceptionsWithoutErrorCode() {
|
||||||
// given
|
// given
|
||||||
@ -195,6 +229,20 @@ class RestResponseEntityExceptionHandlerUnitTest {
|
|||||||
assertThat(errorResponse.getBody().getMessage()).isEqualTo("ERROR: [418] First Line");
|
assertThat(errorResponse.getBody().getMessage()).isEqualTo("ERROR: [418] First Line");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void handleOtherExceptionsWithoutMessage() {
|
||||||
|
// given
|
||||||
|
final var givenThrowable = new Error();
|
||||||
|
final var givenWebRequest = mock(WebRequest.class);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var errorResponse = exceptionHandler.handleOtherExceptions(givenThrowable, givenWebRequest);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(errorResponse.getStatusCodeValue()).isEqualTo(500);
|
||||||
|
assertThat(errorResponse.getBody().getMessage()).isEqualTo("ERROR: [500] java.lang.Error");
|
||||||
|
}
|
||||||
|
|
||||||
public static class NoDisplayNameEntity {
|
public static class NoDisplayNameEntity {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,7 @@ import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
|||||||
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
|
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
|
||||||
|
|
||||||
@SpringBootTest(
|
@SpringBootTest(
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||||
@ -190,36 +189,36 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void globalAdmin_withoutAssumedRole_canAddDebitorWithoutBankAccount() {
|
void globalAdmin_canAddDebitorWithoutJustRequiredData() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0);
|
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0);
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth").get(0);
|
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth").get(0);
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
final var location = RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"partnerUuid": "%s",
|
"partnerUuid": "%s",
|
||||||
"billingContactUuid": "%s",
|
"billingContactUuid": "%s",
|
||||||
"debitorNumber": "%s",
|
"debitorNumber": "%s"
|
||||||
"vatId": "VAT123456",
|
|
||||||
"vatCountryCode": "DE",
|
|
||||||
"vatBusiness": true
|
|
||||||
}
|
}
|
||||||
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), nextDebitorNumber++))
|
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), nextDebitorNumber++))
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.post("http://localhost/api/hs/office/debitors")
|
.post("http://localhost/api/hs/office/debitors")
|
||||||
.then().log().all().assertThat()
|
.then().log().all().assertThat()
|
||||||
.statusCode(201)
|
.statusCode(201)
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("uuid", isUuidValid())
|
.body("uuid", isUuidValid())
|
||||||
.body("vatId", is("VAT123456"))
|
|
||||||
.body("billingContact.label", is(givenContact.getLabel()))
|
.body("billingContact.label", is(givenContact.getLabel()))
|
||||||
.body("partner.person.tradeName", is(givenPartner.getPerson().getTradeName()))
|
.body("partner.person.tradeName", is(givenPartner.getPerson().getTradeName()))
|
||||||
|
.body("vatId", equalTo(null))
|
||||||
|
.body("vatCountryCode", equalTo(null))
|
||||||
|
.body("vatBusiness", equalTo(false))
|
||||||
|
.body("refundBankAccount", equalTo(null))
|
||||||
.header("Location", startsWith("http://localhost"))
|
.header("Location", startsWith("http://localhost"))
|
||||||
.extract().header("Location"); // @formatter:on
|
.extract().header("Location"); // @formatter:on
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user