View Javadoc
1   /*
2    * Copyright 2020-2022 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.exception.spring.boot.autoconfigure.servlet;
18  
19  import static org.assertj.core.api.Assertions.assertThatThrownBy;
20  
21  import feign.Contract;
22  import feign.Feign;
23  import feign.codec.Decoder;
24  import feign.codec.Encoder;
25  import feign.okhttp.OkHttpClient;
26  import java.time.OffsetDateTime;
27  import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension;
28  import org.bremersee.exception.RestApiResponseException;
29  import org.bremersee.exception.feign.FeignClientException;
30  import org.bremersee.exception.feign.FeignClientExceptionErrorDecoder;
31  import org.bremersee.exception.model.RestApiException;
32  import org.bremersee.exception.spring.boot.autoconfigure.servlet.app.TestConfiguration;
33  import org.bremersee.exception.spring.boot.autoconfigure.servlet.app.TestConfiguration.TestRestController;
34  import org.junit.jupiter.api.Test;
35  import org.junit.jupiter.api.extension.ExtendWith;
36  import org.springframework.beans.factory.annotation.Autowired;
37  import org.springframework.boot.test.context.SpringBootTest;
38  import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
39  import org.springframework.boot.test.web.server.LocalServerPort;
40  import org.springframework.boot.web.client.RestTemplateBuilder;
41  import org.springframework.cloud.openfeign.FeignClientsConfiguration;
42  import org.springframework.http.HttpStatus;
43  
44  /**
45   * The servlet integration test.
46   *
47   * @author Christian Bremer
48   */
49  @SpringBootTest(
50      classes = {TestConfiguration.class, FeignClientsConfiguration.class},
51      webEnvironment = WebEnvironment.RANDOM_PORT,
52      properties = {
53          "spring.main.web-application-type=servlet",
54          "spring.application.name=test",
55          "bremersee.exception-mapping.api-paths=/api/**"
56      }
57  )
58  @ExtendWith(SoftAssertionsExtension.class)
59  class ServletIntegrationTest {
60  
61    /**
62     * The rest template builder.
63     */
64    @Autowired
65    RestTemplateBuilder restTemplateBuilder;
66  
67    /**
68     * The Contract.
69     */
70    @Autowired
71    Contract contract;
72  
73    /**
74     * The Encoder.
75     */
76    @Autowired
77    Encoder encoder;
78  
79    /**
80     * The Decoder.
81     */
82    @Autowired
83    Decoder decoder;
84  
85    /**
86     * The Feign client exception error decoder.
87     */
88    @Autowired
89    FeignClientExceptionErrorDecoder feignClientExceptionErrorDecoder;
90  
91    /**
92     * The local server port.
93     */
94    @LocalServerPort
95    int port;
96  
97    /**
98     * Base url of the local server.
99     *
100    * @return the base url of the local server
101    */
102   String baseUrl() {
103     return "http://localhost:" + port;
104   }
105 
106   /**
107    * Fetch rest api exception.
108    */
109   @Test
110   void fetchRestApiException() {
111     RestApiException expected = RestApiException.builder()
112         .status(HttpStatus.CONFLICT.value())
113         .error(HttpStatus.CONFLICT.getReasonPhrase())
114         .errorCode("1234")
115         .errorCodeInherited(false)
116         .message("Entity with identifier [MyEntity] already exists.")
117         .exception("org.bremersee.exception.ServiceException")
118         .application("test")
119         .path("/api/exception")
120         .build();
121     //noinspection ResultOfMethodCallIgnored
122     assertThatThrownBy(() -> restTemplateBuilder.build()
123         .getForEntity(baseUrl() + "/api/exception", String.class)
124         .getBody())
125         .isInstanceOf(RestApiResponseException.class)
126         .extracting(exc -> ((RestApiResponseException) exc).getRestApiException())
127         .usingRecursiveComparison()
128         .ignoringFieldsOfTypes(OffsetDateTime.class)
129         .isEqualTo(expected);
130   }
131 
132   /**
133    * Fetch rest api exception with feign.
134    */
135   @Test
136   void fetchRestApiExceptionWithFeign() {
137     RestApiException expected = RestApiException.builder()
138         .status(HttpStatus.CONFLICT.value())
139         .error(HttpStatus.CONFLICT.getReasonPhrase())
140         .errorCode("1234")
141         .errorCodeInherited(false)
142         .message("Entity with identifier [MyEntity] already exists.")
143         .exception("org.bremersee.exception.ServiceException")
144         .application("test")
145         .path("/api/exception")
146         .build();
147 
148     TestRestController proxy = Feign.builder()
149         .client(new OkHttpClient())
150         .contract(contract)
151         .encoder(encoder)
152         .decoder(decoder)
153         .errorDecoder(feignClientExceptionErrorDecoder)
154         .target(TestRestController.class, baseUrl());
155 
156     assertThatThrownBy(proxy::throwServiceException)
157         .isInstanceOf(FeignClientException.class)
158         .extracting(exc -> ((FeignClientException) exc).getRestApiException())
159         .usingRecursiveComparison()
160         .ignoringFieldsOfTypes(OffsetDateTime.class)
161         .isEqualTo(expected);
162   }
163 
164 }