-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
475 additions
and
5 deletions.
There are no files selected for viewing
3 changes: 0 additions & 3 deletions
3
...est/java/com/getyourguide/openapi/validation/integration/SpringBootTestConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
...ava/com/getyourguide/openapi/validation/integration/ExceptionsNoExceptionHandlerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package com.getyourguide.openapi.validation.integration; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
import com.getyourguide.openapi.validation.test.TestViolationLogger; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
import org.springframework.test.web.reactive.server.WebTestClient; | ||
|
||
@SpringBootTest | ||
@AutoConfigureMockMvc | ||
@ExtendWith(SpringExtension.class) | ||
public class ExceptionsNoExceptionHandlerTest { | ||
|
||
// These test cases test that requests to an endpoint that throws an exception (Mono.error) | ||
// that is not handled by any code (no global error handler either) is correctly intercepted by the library. | ||
|
||
@Autowired | ||
private WebTestClient webTestClient; | ||
|
||
@Autowired | ||
private TestViolationLogger openApiViolationLogger; | ||
|
||
@BeforeEach | ||
public void setup() { | ||
openApiViolationLogger.clearViolations(); | ||
} | ||
|
||
@Test | ||
public void whenTestInvalidQueryParamThenReturns400WithoutViolationLogged() throws Exception { | ||
webTestClient | ||
.get().uri("/test?date=not-a-date") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().isBadRequest() | ||
.expectBody() | ||
.jsonPath("$.status").isEqualTo(400) | ||
.jsonPath("$.path").isEqualTo("/test") | ||
.jsonPath("$.error").isEqualTo("Bad Request"); | ||
Thread.sleep(100); | ||
|
||
assertEquals(0, openApiViolationLogger.getViolations().size()); | ||
} | ||
|
||
@Test | ||
public void whenTestThrowExceptionWithResponseStatusThenReturns400WithoutViolationLogged() | ||
throws Exception { | ||
webTestClient | ||
.get().uri("/test?testCase=throwExceptionWithResponseStatus") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().isBadRequest() | ||
.expectBody() | ||
.jsonPath("$.status").isEqualTo(400) | ||
.jsonPath("$.path").isEqualTo("/test") | ||
.jsonPath("$.error").isEqualTo("Bad Request"); | ||
Thread.sleep(100); | ||
|
||
assertEquals(0, openApiViolationLogger.getViolations().size()); | ||
} | ||
|
||
@Test | ||
public void whenTestThrowExceptionWithoutResponseStatusThenReturns500WithoutViolationLogged() | ||
throws Exception { | ||
webTestClient | ||
.get().uri("/test?testCase=throwExceptionWithoutResponseStatus") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().is5xxServerError() | ||
.expectBody() | ||
.jsonPath("$.status").isEqualTo(500) | ||
.jsonPath("$.path").isEqualTo("/test") | ||
.jsonPath("$.error").isEqualTo("Internal Server Error"); | ||
Thread.sleep(100); | ||
|
||
assertEquals(0, openApiViolationLogger.getViolations().size()); | ||
} | ||
} |
111 changes: 111 additions & 0 deletions
111
...a/com/getyourguide/openapi/validation/integration/ExceptionsWithExceptionHandlerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package com.getyourguide.openapi.validation.integration; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
import com.getyourguide.openapi.validation.test.TestViolationLogger; | ||
import com.getyourguide.openapi.validation.test.exception.WithResponseStatusException; | ||
import com.getyourguide.openapi.validation.test.exception.WithoutResponseStatusException; | ||
import com.getyourguide.openapi.validation.test.openapi.webflux.model.BadRequestResponse; | ||
import java.util.Optional; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
import org.springframework.test.web.reactive.server.WebTestClient; | ||
import org.springframework.web.bind.annotation.ControllerAdvice; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; | ||
import org.springframework.web.server.ServerWebInputException; | ||
|
||
@SpringBootTest(classes = { | ||
SpringBootTestConfiguration.class, | ||
ExceptionsWithExceptionHandlerTest.ExceptionHandlerConfiguration.class, | ||
}) | ||
@AutoConfigureMockMvc | ||
@ExtendWith(SpringExtension.class) | ||
public class ExceptionsWithExceptionHandlerTest { | ||
|
||
@Autowired | ||
private WebTestClient webTestClient; | ||
|
||
@Autowired | ||
private TestViolationLogger openApiViolationLogger; | ||
|
||
@BeforeEach | ||
public void setup() { | ||
openApiViolationLogger.clearViolations(); | ||
} | ||
|
||
@Test | ||
public void whenTestInvalidQueryParamThenReturns400WithoutViolationLogged() throws Exception { | ||
webTestClient | ||
.get().uri("/test?date=not-a-date") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().isBadRequest() | ||
.expectBody().jsonPath("$.error").isEqualTo("ServerWebInputException"); | ||
Thread.sleep(100); | ||
|
||
assertEquals(0, openApiViolationLogger.getViolations().size()); | ||
} | ||
|
||
@Test | ||
public void whenTestThrowExceptionWithResponseStatusThenReturns400WithoutViolationLogged() | ||
throws Exception { | ||
webTestClient | ||
.get().uri("/test?testCase=throwExceptionWithResponseStatus") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().isBadRequest() | ||
.expectBody().jsonPath("$.error").isEqualTo("Unhandled exception"); | ||
Thread.sleep(100); | ||
|
||
assertEquals(0, openApiViolationLogger.getViolations().size()); | ||
} | ||
|
||
@Test | ||
public void whenTestThrowExceptionWithoutResponseStatusThenReturns500WithoutViolationLogged() | ||
throws Exception { | ||
webTestClient | ||
.get().uri("/test?testCase=throwExceptionWithoutResponseStatus") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().is5xxServerError() | ||
.expectBody().isEmpty(); | ||
Thread.sleep(100); | ||
|
||
// Note: We return no body on purpose in the exception handler below to test this violation appears. | ||
assertEquals(1, openApiViolationLogger.getViolations().size()); | ||
var violation = openApiViolationLogger.getViolations().get(0); | ||
assertEquals("validation.response.body.missing", violation.getRule()); | ||
assertEquals(Optional.of(500), violation.getResponseStatus()); | ||
} | ||
|
||
@ControllerAdvice | ||
public static class ExceptionHandlerConfiguration { | ||
@ExceptionHandler(ServerWebInputException.class) | ||
public ResponseEntity<?> handle(ServerWebInputException exception) { | ||
return ResponseEntity.badRequest().body(new BadRequestResponse().error("ServerWebInputException")); | ||
} | ||
|
||
@ExceptionHandler(WithResponseStatusException.class) | ||
public ResponseEntity<?> handle(WithResponseStatusException exception) { | ||
return ResponseEntity.badRequest().body(new BadRequestResponse().error("Unhandled exception")); | ||
} | ||
|
||
@ExceptionHandler(WithoutResponseStatusException.class) | ||
public ResponseEntity<?> handle(WithoutResponseStatusException exception) { | ||
return ResponseEntity.internalServerError().build(); | ||
} | ||
|
||
@ExceptionHandler(MethodArgumentTypeMismatchException.class) | ||
public ResponseEntity<?> handle(MethodArgumentTypeMismatchException exception) { | ||
return ResponseEntity.badRequest().body(new BadRequestResponse().error("Invalid parameter")); | ||
} | ||
} | ||
} |
146 changes: 146 additions & 0 deletions
146
...ava/com/getyourguide/openapi/validation/integration/OpenApiValidationIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package com.getyourguide.openapi.validation.integration; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
|
||
import com.getyourguide.openapi.validation.api.model.OpenApiViolation; | ||
import com.getyourguide.openapi.validation.test.TestViolationLogger; | ||
import com.getyourguide.openapi.validation.test.openapi.webflux.model.TestResponse; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import javax.annotation.Nullable; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
import org.springframework.test.web.reactive.server.WebTestClient; | ||
|
||
@SpringBootTest | ||
@AutoConfigureMockMvc | ||
@ExtendWith(SpringExtension.class) | ||
public class OpenApiValidationIntegrationTest { | ||
@Autowired | ||
private WebTestClient webTestClient; | ||
|
||
@Autowired | ||
private TestViolationLogger openApiViolationLogger; | ||
|
||
@BeforeEach | ||
public void setup() { | ||
openApiViolationLogger.clearViolations(); | ||
} | ||
|
||
@Test | ||
public void whenTestSuccessfulResponseThenShouldNotLogViolation() throws Exception { | ||
webTestClient | ||
.get().uri("/test") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().isOk() | ||
.expectBody(TestResponse.class) | ||
.consumeWith(serverResponse -> { | ||
assertNotNull(serverResponse.getResponseBody()); | ||
assertEquals("test", serverResponse.getResponseBody().getValue()); | ||
}); | ||
Thread.sleep(100); | ||
|
||
assertEquals(0, openApiViolationLogger.getViolations().size()); | ||
} | ||
|
||
@Test | ||
public void whenTestValidRequestWithInvalidResponseThenShouldReturnSuccessAndLogViolation() throws Exception { | ||
webTestClient | ||
.get().uri("/test?value=invalid-response-value!") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().isOk() | ||
.expectBody(TestResponse.class) | ||
.consumeWith(serverResponse -> { | ||
assertNotNull(serverResponse.getResponseBody()); | ||
assertEquals("invalid-response-value!", serverResponse.getResponseBody().getValue()); | ||
}); | ||
Thread.sleep(100); | ||
|
||
assertEquals(1, openApiViolationLogger.getViolations().size()); | ||
var violation = openApiViolationLogger.getViolations().get(0); | ||
assertEquals("validation.response.body.schema.pattern", violation.getRule()); | ||
assertEquals(Optional.of(200), violation.getResponseStatus()); | ||
assertEquals(Optional.of("/value"), violation.getInstance()); | ||
} | ||
|
||
@Test | ||
public void whenTestInvalidRequestNotHandledBySpringBootThenShouldReturnSuccessAndLogViolation() throws Exception { | ||
webTestClient | ||
.post().uri("/test") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.contentType(MediaType.APPLICATION_JSON) | ||
.bodyValue("{ \"value\": 1 }") | ||
.exchange() | ||
.expectStatus().isNoContent() | ||
.expectBody().isEmpty(); | ||
Thread.sleep(100); | ||
|
||
assertEquals(1, openApiViolationLogger.getViolations().size()); | ||
var violation = openApiViolationLogger.getViolations().get(0); | ||
assertEquals("validation.request.body.schema.type", violation.getRule()); | ||
assertEquals(Optional.of(204), violation.getResponseStatus()); | ||
assertEquals(Optional.of("/value"), violation.getInstance()); | ||
} | ||
|
||
|
||
@Test | ||
public void whenTestInvalidRequestAndInvalidResponseThenShouldReturnSuccessAndLogViolation() throws Exception { | ||
webTestClient | ||
.post().uri("/test") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.contentType(MediaType.APPLICATION_JSON) | ||
.bodyValue("{ \"value\": 1, \"responseStatusCode\": 200 }") | ||
.exchange() | ||
.expectStatus().isOk() | ||
.expectBody(TestResponse.class) | ||
.consumeWith(serverResponse -> { | ||
assertNotNull(serverResponse.getResponseBody()); | ||
assertEquals("1", serverResponse.getResponseBody().getValue()); | ||
}); | ||
Thread.sleep(100); | ||
|
||
var violations = openApiViolationLogger.getViolations(); | ||
assertEquals(2, violations.size()); | ||
var violation = getViolationByRule(violations, "validation.response.body.schema.pattern"); | ||
assertNotNull(violation); | ||
assertEquals(Optional.of(200), violation.getResponseStatus()); | ||
assertEquals(Optional.of("/value"), violation.getInstance()); | ||
var violation2 = getViolationByRule(violations, "validation.request.body.schema.type"); | ||
assertNotNull(violation2); | ||
assertEquals(Optional.of(200), violation2.getResponseStatus()); | ||
assertEquals(Optional.of("/value"), violation2.getInstance()); | ||
} | ||
|
||
@Test | ||
public void whenTestOptionsCallThenShouldNotValidate() throws Exception { | ||
// Note: Options is not in the spec and would report a violation if it was validated. | ||
webTestClient | ||
.options().uri("/test") | ||
.accept(MediaType.APPLICATION_JSON) | ||
.exchange() | ||
.expectStatus().isOk() | ||
.expectBody().isEmpty(); | ||
Thread.sleep(100); | ||
|
||
assertEquals(0, openApiViolationLogger.getViolations().size()); | ||
} | ||
|
||
// TODO Add test that fails on request violation immediately (maybe needs separate test class & setup) should not log violation | ||
|
||
@Nullable | ||
private OpenApiViolation getViolationByRule(List<OpenApiViolation> violations, String rule) { | ||
return violations.stream() | ||
.filter(violation -> violation.getRule().equals(rule)) | ||
.findFirst() | ||
.orElse(null); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...est/java/com/getyourguide/openapi/validation/integration/SpringBootTestConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.getyourguide.openapi.validation.integration; | ||
|
||
import com.getyourguide.openapi.validation.test.DefaultSpringBootTestConfiguration; | ||
import org.springframework.boot.SpringBootConfiguration; | ||
import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter; | ||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | ||
import org.springframework.boot.context.TypeExcludeFilter; | ||
import org.springframework.context.annotation.ComponentScan; | ||
import org.springframework.context.annotation.FilterType; | ||
|
||
@SpringBootConfiguration | ||
@EnableAutoConfiguration | ||
@ComponentScan(excludeFilters = { | ||
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), | ||
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) | ||
}) | ||
public class SpringBootTestConfiguration extends DefaultSpringBootTestConfiguration { | ||
} |
Oops, something went wrong.