Skip to content

Commit f9dbee2

Browse files
committed
Use correct header for exception type in FallbackHeadersGatewayFilterFactory
Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
1 parent edc7993 commit f9dbee2

2 files changed

Lines changed: 154 additions & 1 deletion

File tree

spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/FallbackHeadersGatewayFilterFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private ServerWebExchange addFallbackHeaders(Config config, ServerWebExchange ex
6363
Throwable executionException) {
6464

6565
ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate();
66-
requestBuilder.header(config.getExecutionExceptionMessageHeaderName(), executionException.getClass().getName());
66+
requestBuilder.header(config.getExecutionExceptionTypeHeaderName(), executionException.getClass().getName());
6767
String executionMessage = executionException.getMessage();
6868
requestBuilder.header(config.getExecutionExceptionMessageHeaderName(),
6969
executionMessage != null ? executionMessage : "");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Copyright 2013-present 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+
* https://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.springframework.cloud.gateway.filter.factory;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.mockito.ArgumentCaptor;
21+
import reactor.core.publisher.Mono;
22+
23+
import org.springframework.cloud.gateway.filter.GatewayFilter;
24+
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
25+
import org.springframework.http.HttpHeaders;
26+
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
27+
import org.springframework.mock.web.server.MockServerWebExchange;
28+
import org.springframework.web.server.ServerWebExchange;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.mockito.ArgumentMatchers.any;
32+
import static org.mockito.Mockito.mock;
33+
import static org.mockito.Mockito.verify;
34+
import static org.mockito.Mockito.verifyNoMoreInteractions;
35+
import static org.mockito.Mockito.when;
36+
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR;
37+
38+
/**
39+
* Tests for {@link FallbackHeadersGatewayFilterFactory}.
40+
*
41+
* @author Spring Cloud Gateway Team
42+
*/
43+
class FallbackHeadersGatewayFilterFactoryTests {
44+
45+
private final FallbackHeadersGatewayFilterFactory factory = new FallbackHeadersGatewayFilterFactory();
46+
47+
private final GatewayFilterChain chain = mock(GatewayFilterChain.class);
48+
49+
@Test
50+
void shouldSetExecutionExceptionTypeHeader() {
51+
FallbackHeadersGatewayFilterFactory.Config config = new FallbackHeadersGatewayFilterFactory.Config();
52+
GatewayFilter filter = factory.apply(config);
53+
54+
RuntimeException exception = new RuntimeException("Test exception message");
55+
ServerWebExchange exchange = MockServerWebExchange
56+
.from(MockServerHttpRequest.get("http://localhost/get").build());
57+
exchange.getAttributes().put(CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR, exception);
58+
59+
ArgumentCaptor<ServerWebExchange> captor = ArgumentCaptor.forClass(ServerWebExchange.class);
60+
when(chain.filter(captor.capture())).thenReturn(Mono.empty());
61+
62+
filter.filter(exchange, chain).block();
63+
64+
verify(chain).filter(any(ServerWebExchange.class));
65+
verifyNoMoreInteractions(chain);
66+
67+
ServerWebExchange filteredExchange = captor.getValue();
68+
HttpHeaders headers = filteredExchange.getRequest().getHeaders();
69+
70+
assertThat(headers.get(config.getExecutionExceptionTypeHeaderName()))
71+
.containsExactly(RuntimeException.class.getName());
72+
assertThat(headers.get(config.getExecutionExceptionMessageHeaderName()))
73+
.containsExactly("Test exception message");
74+
}
75+
76+
@Test
77+
void shouldSetExecutionExceptionTypeAndMessageHeadersDistinctly() {
78+
FallbackHeadersGatewayFilterFactory.Config config = new FallbackHeadersGatewayFilterFactory.Config();
79+
config.setExecutionExceptionTypeHeaderName("Custom-Exception-Type");
80+
config.setExecutionExceptionMessageHeaderName("Custom-Exception-Message");
81+
GatewayFilter filter = factory.apply(config);
82+
83+
IllegalStateException exception = new IllegalStateException("Custom error message");
84+
ServerWebExchange exchange = MockServerWebExchange
85+
.from(MockServerHttpRequest.get("http://localhost/get").build());
86+
exchange.getAttributes().put(CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR, exception);
87+
88+
ArgumentCaptor<ServerWebExchange> captor = ArgumentCaptor.forClass(ServerWebExchange.class);
89+
when(chain.filter(captor.capture())).thenReturn(Mono.empty());
90+
91+
filter.filter(exchange, chain).block();
92+
93+
verify(chain).filter(any(ServerWebExchange.class));
94+
verifyNoMoreInteractions(chain);
95+
96+
ServerWebExchange filteredExchange = captor.getValue();
97+
HttpHeaders headers = filteredExchange.getRequest().getHeaders();
98+
99+
assertThat(headers.get("Custom-Exception-Type")).containsExactly(IllegalStateException.class.getName());
100+
assertThat(headers.get("Custom-Exception-Message")).containsExactly("Custom error message");
101+
assertThat(headers.get("Custom-Exception-Type")).isNotEqualTo(headers.get("Custom-Exception-Message"));
102+
}
103+
104+
@Test
105+
void shouldHandleExceptionWithNullMessage() {
106+
FallbackHeadersGatewayFilterFactory.Config config = new FallbackHeadersGatewayFilterFactory.Config();
107+
GatewayFilter filter = factory.apply(config);
108+
109+
NullPointerException exception = new NullPointerException();
110+
ServerWebExchange exchange = MockServerWebExchange
111+
.from(MockServerHttpRequest.get("http://localhost/get").build());
112+
exchange.getAttributes().put(CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR, exception);
113+
114+
ArgumentCaptor<ServerWebExchange> captor = ArgumentCaptor.forClass(ServerWebExchange.class);
115+
when(chain.filter(captor.capture())).thenReturn(Mono.empty());
116+
117+
filter.filter(exchange, chain).block();
118+
119+
verify(chain).filter(any(ServerWebExchange.class));
120+
verifyNoMoreInteractions(chain);
121+
122+
ServerWebExchange filteredExchange = captor.getValue();
123+
HttpHeaders headers = filteredExchange.getRequest().getHeaders();
124+
125+
assertThat(headers.get(config.getExecutionExceptionTypeHeaderName()))
126+
.containsExactly(NullPointerException.class.getName());
127+
assertThat(headers.get(config.getExecutionExceptionMessageHeaderName())).containsExactly("");
128+
}
129+
130+
@Test
131+
void shouldNotAddHeadersWhenNoException() {
132+
FallbackHeadersGatewayFilterFactory.Config config = new FallbackHeadersGatewayFilterFactory.Config();
133+
GatewayFilter filter = factory.apply(config);
134+
135+
ServerWebExchange exchange = MockServerWebExchange
136+
.from(MockServerHttpRequest.get("http://localhost/get").build());
137+
138+
ArgumentCaptor<ServerWebExchange> captor = ArgumentCaptor.forClass(ServerWebExchange.class);
139+
when(chain.filter(captor.capture())).thenReturn(Mono.empty());
140+
141+
filter.filter(exchange, chain).block();
142+
143+
verify(chain).filter(any(ServerWebExchange.class));
144+
verifyNoMoreInteractions(chain);
145+
146+
ServerWebExchange filteredExchange = captor.getValue();
147+
HttpHeaders headers = filteredExchange.getRequest().getHeaders();
148+
149+
assertThat(headers.get(config.getExecutionExceptionTypeHeaderName())).isNull();
150+
assertThat(headers.get(config.getExecutionExceptionMessageHeaderName())).isNull();
151+
}
152+
153+
}

0 commit comments

Comments
 (0)