diff --git a/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/ExceptionHandling.java b/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/ExceptionHandling.java index ff3c4629..cd98bbed 100644 --- a/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/ExceptionHandling.java +++ b/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/ExceptionHandling.java @@ -8,6 +8,6 @@ @API(status = INTERNAL) @ControllerAdvice -final class ExceptionHandling implements ProblemHandling { +public final class ExceptionHandling implements ProblemHandling { } diff --git a/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/ProblemAutoConfiguration.java b/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/ProblemAutoConfiguration.java index a29abb04..4713a7ab 100644 --- a/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/ProblemAutoConfiguration.java +++ b/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/ProblemAutoConfiguration.java @@ -19,7 +19,7 @@ public class ProblemAutoConfiguration { @Bean @ConditionalOnMissingBean(AdviceTrait.class) - public AdviceTrait exceptionHandling() { + public ExceptionHandling exceptionHandling() { return new ExceptionHandling(); } diff --git a/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityAutoConfiguration.java b/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityAutoConfiguration.java index 351e3022..31aa6845 100644 --- a/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityAutoConfiguration.java +++ b/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityAutoConfiguration.java @@ -33,7 +33,7 @@ public class ProblemSecurityAutoConfiguration { @Bean @ConditionalOnMissingBean(AdviceTrait.class) - public AdviceTrait securityExceptionHandling() { + public SecurityExceptionHandling securityExceptionHandling() { return new SecurityExceptionHandling(); } diff --git a/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/security/SecurityExceptionHandling.java b/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/security/SecurityExceptionHandling.java index d0315a08..02ba2320 100644 --- a/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/security/SecurityExceptionHandling.java +++ b/problem-spring-web-autoconfigure/src/main/java/org/zalando/problem/spring/web/autoconfigure/security/SecurityExceptionHandling.java @@ -9,7 +9,7 @@ @API(status = INTERNAL) @ControllerAdvice -final class SecurityExceptionHandling +public final class SecurityExceptionHandling implements ProblemHandling, SecurityAdviceTrait { } diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/WebApplicationTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/WebApplicationTest.java deleted file mode 100644 index ffd9ef84..00000000 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/WebApplicationTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.zalando.problem.spring.web.autoconfigure; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Configuration; -import org.zalando.problem.jackson.ProblemModule; -import org.zalando.problem.spring.web.advice.AdviceTrait; -import org.zalando.problem.violations.ConstraintViolationProblemModule; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class) -final class WebApplicationTest { - - @Configuration - static class TestApplication { - - } - - @Test - void shouldConfigureExceptionHandling( - @Autowired final AdviceTrait trait) { - assertThat(trait).isExactlyInstanceOf(ExceptionHandling.class); - } - - @Test - void shouldConfigureProblemModule( - @Autowired final ProblemModule module) { - assertThat(module).isNotNull(); - } - - @Test - void shouldConfigureConstraintViolationProblemModule( - @Autowired final ConstraintViolationProblemModule module) { - assertThat(module).isNotNull(); - } - -} diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/SecurityTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/SecurityTest.java deleted file mode 100644 index cd53f4b8..00000000 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/SecurityTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.zalando.problem.spring.web.autoconfigure.security; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.web.servlet.MockMvc; - -import static org.hamcrest.Matchers.is; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@SpringBootTest -@AutoConfigureMockMvc -@DirtiesContext -final class SecurityTest { - @Autowired - private MockMvc mockMvc; - - @Test - void shouldConfigureExceptionHandling() throws Exception{ - mockMvc.perform(get("/not-exists-url")) - .andExpect(status().isUnauthorized()) - .andExpect(jsonPath("$.status", is(401))) - .andExpect(jsonPath("$.title", is("Unauthorized"))) - .andExpect(jsonPath("$.detail", is("Full authentication is required to access this resource"))); - } - - @SpringBootApplication - static class TestApp { - @Configuration(proxyBeanMethods = false) - class WebSecurityConfig extends WebSecurityConfigurerAdapter { - @Override - protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().authenticated(); - } - } - } -} diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/CustomAdviceTraitTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/CustomAdviceTraitTest.java similarity index 95% rename from problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/CustomAdviceTraitTest.java rename to problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/CustomAdviceTraitTest.java index 3457876b..373d162a 100644 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/CustomAdviceTraitTest.java +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/CustomAdviceTraitTest.java @@ -1,4 +1,4 @@ -package org.zalando.problem.spring.web.autoconfigure; +package org.zalando.problem.spring.web.autoconfiguretests; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/CustomWebMvcApplicationTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/CustomWebMvcApplicationTest.java similarity index 95% rename from problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/CustomWebMvcApplicationTest.java rename to problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/CustomWebMvcApplicationTest.java index c6220e42..19a03ff4 100644 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/CustomWebMvcApplicationTest.java +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/CustomWebMvcApplicationTest.java @@ -1,4 +1,4 @@ -package org.zalando.problem.spring.web.autoconfigure; +package org.zalando.problem.spring.web.autoconfiguretests; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/NonWebApplicationTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/NonWebApplicationTest.java similarity index 95% rename from problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/NonWebApplicationTest.java rename to problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/NonWebApplicationTest.java index 0673be35..206e646a 100644 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/NonWebApplicationTest.java +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/NonWebApplicationTest.java @@ -1,4 +1,4 @@ -package org.zalando.problem.spring.web.autoconfigure; +package org.zalando.problem.spring.web.autoconfiguretests; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/WebApplicationTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/WebApplicationTest.java new file mode 100644 index 00000000..91e191c0 --- /dev/null +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/WebApplicationTest.java @@ -0,0 +1,66 @@ +package org.zalando.problem.spring.web.autoconfiguretests; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.zalando.problem.jackson.ProblemModule; +import org.zalando.problem.spring.web.advice.AdviceTrait; +import org.zalando.problem.spring.web.autoconfigure.ExceptionHandling; +import org.zalando.problem.violations.ConstraintViolationProblemModule; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class) +final class WebApplicationTest { + + @Autowired + private MockMvc mockMvc; + + @Configuration + static class TestApplication { + @RestController + static class Controller { + @GetMapping("/exception") + void getException() { + throw new RuntimeException("An exception from GET"); + } + } + } + + @Test + void shouldConfigureExceptionHandling( + @Autowired final AdviceTrait trait) throws Exception { + assertThat(trait).isExactlyInstanceOf(ExceptionHandling.class); + mockMvc.perform(get("/exception")) + .andExpect(status().isInternalServerError()) + .andExpect(jsonPath("$.status", is(500))) + .andExpect(jsonPath("$.title", is("Internal Server Error"))) + .andExpect(jsonPath("$.detail", is("An exception from GET"))); + } + + @Test + void shouldConfigureProblemModule( + @Autowired final ProblemModule module) { + assertThat(module).isNotNull(); + } + + @Test + void shouldConfigureConstraintViolationProblemModule( + @Autowired final ConstraintViolationProblemModule module) { + assertThat(module).isNotNull(); + } + +} diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/NoConfigurerSecurityTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/NoConfigurerSecurityTest.java similarity index 95% rename from problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/NoConfigurerSecurityTest.java rename to problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/NoConfigurerSecurityTest.java index ced2a350..1e1b0356 100644 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/NoConfigurerSecurityTest.java +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/NoConfigurerSecurityTest.java @@ -1,4 +1,4 @@ -package org.zalando.problem.spring.web.autoconfigure.security; +package org.zalando.problem.spring.web.autoconfiguretests.security; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemHttpConfigurerTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemHttpConfigurerTest.java similarity index 97% rename from problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemHttpConfigurerTest.java rename to problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemHttpConfigurerTest.java index 79254fb2..24811e8a 100644 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemHttpConfigurerTest.java +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemHttpConfigurerTest.java @@ -1,4 +1,4 @@ -package org.zalando.problem.spring.web.autoconfigure.security; +package org.zalando.problem.spring.web.autoconfiguretests.security; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -14,6 +14,7 @@ import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.ClassUtils; import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport; +import org.zalando.problem.spring.web.autoconfigure.security.ProblemHttpConfigurer; import java.util.HashMap; import java.util.Map; diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityAutoConfigurationTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemSecurityAutoConfigurationTest.java similarity index 89% rename from problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityAutoConfigurationTest.java rename to problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemSecurityAutoConfigurationTest.java index e89bf318..e75176ad 100644 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityAutoConfigurationTest.java +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemSecurityAutoConfigurationTest.java @@ -1,4 +1,4 @@ -package org.zalando.problem.spring.web.autoconfigure.security; +package org.zalando.problem.spring.web.autoconfiguretests.security; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -13,6 +13,9 @@ import org.zalando.problem.spring.web.advice.AdviceTrait; import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport; import org.zalando.problem.spring.web.autoconfigure.ProblemAutoConfiguration; +import org.zalando.problem.spring.web.autoconfigure.security.ProblemSecurityAutoConfiguration; +import org.zalando.problem.spring.web.autoconfigure.security.ProblemSecurityBeanPostProcessor; +import org.zalando.problem.spring.web.autoconfigure.security.SecurityExceptionHandling; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityBeanPostProcessorTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemSecurityBeanPostProcessorTest.java similarity index 96% rename from problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityBeanPostProcessorTest.java rename to problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemSecurityBeanPostProcessorTest.java index 8020cb81..4ef0fe77 100644 --- a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfigure/security/ProblemSecurityBeanPostProcessorTest.java +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/ProblemSecurityBeanPostProcessorTest.java @@ -1,4 +1,4 @@ -package org.zalando.problem.spring.web.autoconfigure.security; +package org.zalando.problem.spring.web.autoconfiguretests.security; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -10,6 +10,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.test.util.ReflectionTestUtils; import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport; +import org.zalando.problem.spring.web.autoconfigure.security.ProblemSecurityBeanPostProcessor; import java.util.HashMap; import java.util.function.Consumer; diff --git a/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/SecurityTest.java b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/SecurityTest.java new file mode 100644 index 00000000..a8a57145 --- /dev/null +++ b/problem-spring-web-autoconfigure/src/test/java/org/zalando/problem/spring/web/autoconfiguretests/security/SecurityTest.java @@ -0,0 +1,89 @@ +package org.zalando.problem.spring.web.autoconfiguretests.security; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import org.zalando.problem.spring.common.MediaTypes; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +@DirtiesContext +final class SecurityTest { + @Autowired + private MockMvc mockMvc; + + @Test + void shouldConfigureExceptionHandling() throws Exception { + mockMvc.perform(get("/not-exists-url")) + .andExpect(status().isUnauthorized()) + .andExpect(jsonPath("$.status", is(401))) + .andExpect(jsonPath("$.title", is("Unauthorized"))) + .andExpect(jsonPath("$.detail", is("Full authentication is required to access this resource"))); + } + + @Test + void shouldRespectResponseStatus() throws Exception { + mockMvc.perform(get("/custom-not-found")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.status", is(404))) + .andExpect(jsonPath("$.title", is("Not Found"))) + .andExpect(jsonPath("$.detail", is("Custom NotFoundException"))); + } + + @Test + void shouldReturnCorrectContentType() throws Exception { + mockMvc.perform(get("/custom-not-found").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.PROBLEM_VALUE)) + .andExpect(jsonPath("$.status", is(404))) + .andExpect(jsonPath("$.title", is("Not Found"))) + .andExpect(jsonPath("$.detail", is("Custom NotFoundException"))); + } + + @SpringBootApplication + static class TestApp { + @RestController + static class Controller { + @GetMapping("/custom-not-found") + void getException() { + throw new NotFoundException(); + } + } + + @ResponseStatus(HttpStatus.NOT_FOUND) + static class NotFoundException extends RuntimeException { + public NotFoundException() { + super("Custom NotFoundException"); + } + } + + @Configuration(proxyBeanMethods = false) + static class WebSecurityConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .mvcMatchers("/custom-not-found").permitAll() + .anyRequest().authenticated(); + } + } + } +}