Как вы тестируете RouteLocator Spring Cloud Gateway?JAVA

Программисты JAVA общаются здесь
Anonymous
Как вы тестируете RouteLocator Spring Cloud Gateway?

Сообщение Anonymous »

Я хочу протестировать свой RouteLocator. Я попытался сделать это аналогично тому, как мы тестируем конечные точки в WebFluxTest. Вот мои
Попытки
Попытка №1

Код: Выделить всё

package com.example.gatewaydemo.filter;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;

import java.util.List;
import java.util.UUID;

@WebFluxTest(controllers = GatewayTest.Config.class)
@ContextConfiguration(classes = GatewayTest.Config.class)
public class GatewayTest {
@Autowired
WebTestClient client;

@Test
void test() {
client.get()
.uri("/original-path")
.exchange()
.expectStatus().isEqualTo(HttpStatus.OK);
}

@Configuration
@EnableAutoConfiguration
static class Config {
@Bean
public RouterFunction routerFunction() {
return RouterFunctions.route()
.GET("/eventual-path", request -> ServerResponse.status(HttpStatus.OK).build())
.build();
}

@Bean
public RouteLocator routeLocator() {
// suppose I want to test this RouteLocator
GatewayFilter rewriteFilter = new RewritePathGatewayFilterFactory()
.apply(config -> config.setRegexp("/original-path")
.setReplacement("/eventual-path"));
Route route = Route.async()
.id(UUID.randomUUID().toString())
.filter(new OrderedGatewayFilter(rewriteFilter, 0)) // it's important to wrap
.predicate(new PathRoutePredicateFactory()
.apply(config -> config.setPatterns(List.of("/original-path"))))
.uri("http://localhost:8080")
.build();
return () -> Flux.just(route);
}
}
}

Код: Выделить всё


4.0.0

org.springframework.boot
spring-boot-starter-parent
3.1.5
  

com.example
gatewaydemo
0.0.1-SNAPSHOT
gatewaydemo
gatewaydemo

17
2022.0.4



org.springframework.cloud
spring-cloud-starter


org.springframework.cloud
spring-cloud-starter-gateway


org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test





org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import







org.springframework.boot
spring-boot-maven-plugin



org.projectlombok
lombok








Однако тест не пройден из-за ошибки 404.

Код: Выделить всё

2024-03-19T18:11:02.607+03:00 ERROR 14904 --- [           main] o.s.t.w.reactive.server.ExchangeResult   : Request details for assertion failure:

> GET /original-path
> WebTestClient-Request-Id: [1]

No content

< 404 NOT_FOUND Not Found
< Content-Type: [application/json]
< Content-Length: [140]

{"timestamp":"2024-03-19T15:11:02.447+00:00","path":"/original-path","status":404,"error":"Not Found","message":null,"requestId":"37ea34a7"}
Я твердо уверен, что мой RouteLocator игнорируется. Возможно, это связано с @WebFluxTest, который не предназначен для его получения
Попытка №2

Код: Выделить всё

@SpringBootTest
@AutoConfigureWebTestClient
public class GatewayTest {
// the rest is the same
Тест по-прежнему не пройден, но на этот раз это 500. Кажется, сервер не прослушивает порт 8080

Код: Выделить всё

2024-03-19T18:36:20.582+03:00 ERROR 8860 --- [ctor-http-nio-2] a.w.r.e.AbstractErrorWebExceptionHandler : [c0fdf3a]  500 Server Error for HTTP GET "/original-path"

io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/127.0.0.1:8080
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ HTTP GET "/original-path" [ExceptionHandlingWebHandler]
Original Stack Trace:
Caused by: java.net.ConnectException: Connection refused: no further information
at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) ~[na:na]
at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:946) ~[na:na]
at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:337) ~[netty-transport-4.1.100.Final.jar:4.1.100.Final]
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334) ~[netty-transport-4.1.100.Final.jar:4.1.100.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:776) ~[netty-transport-4.1.100.Final.jar:4.1.100.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[netty-transport-4.1.100.Final.jar:4.1.100.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[netty-transport-4.1.100.Final.jar:4.1.100.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.100.Final.jar:4.1.100.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.100.Final.jar:4.1.100.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.100.Final.jar:4.1.100.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.100.Final.jar:4.1.100.Final]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

2024-03-19T18:36:20.699+03:00 ERROR 8860 --- [           main] o.s.t.w.reactive.server.ExchangeResult   : Request details for assertion failure:

> GET /original-path
> WebTestClient-Request-Id: [1]

No content

< 500 INTERNAL_SERVER_ERROR Internal Server Error
< Content-Type: [application/json]
< Content-Length: [136]

{"timestamp":"2024-03-19T15:36:20.576+00:00","path":"/original-path","status":500,"error":"Internal Server Error","requestId":"c0fdf3a"}
Попытка №3

Код: Выделить всё

webEnvironment
, RANDOM_PORT

Код: Выделить всё

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
public class GatewayTest {
@Autowired
WebTestClient client;

@LocalServerPort
int port;

@Test
void test() {
client.get()
.uri("/original-path")
.exchange()
.expectStatus().isEqualTo(HttpStatus.OK);
}

@Configuration
@EnableAutoConfiguration
class Config {
// the same RouterFunction

@Bean
public RouteLocator routeLocator() {
GatewayFilter rewriteFilter = new RewritePathGatewayFilterFactory()
.apply(config -> config.setRegexp("/original-path")
.setReplacement("/eventual-path"));
Route route = Route.async()
.id(UUID.randomUUID().toString())
.filter(new OrderedGatewayFilter(rewriteFilter, 0))
.predicate(new PathRoutePredicateFactory()
.apply(config -> config.setPatterns(List.of("/original-path"))))
.uri("http://localhost:" + port)
.build();
return () -> Flux.just(route);
}
}
}
Опять 404

Код: Выделить всё

2024-03-19T19:12:15.447+03:00 ERROR 3760 --- [           main] o.s.t.w.reactive.server.ExchangeResult   : Request details for assertion failure:

>  GET /original-path
> WebTestClient-Request-Id: [1]

No content

< 404 NOT_FOUND Not Found
< Content-Type: [application/json]
< Content-Length: [140]

{"timestamp":"2024-03-19T16:12:15.328+00:00","path":"/original-path","status":404,"error":"Not Found","message":null,"requestId":"5930e136"}
Исследование
ТАК
Я изучил несколько ответов по этой теме
  • "Юнит-тест Spring Cloud Gateway RouteLocator customRouteLocator (RouteLocatorBuilderrouteLocatorBuilder)". Мне не нравится решение. Он либо предлагает протестировать RouteLocator, автоматически созданный на основе встроенных свойств

Код: Выделить всё

@RunWith(SpringRunner.class)
@SpringBootTest(properties = {
"spring.cloud.gateway.routes[0].id=test",
"spring.cloud.gateway.routes[0].uri=http://localhost:8081",
"spring.cloud.gateway.routes[0].predicates[0]=Path=/test/**",
}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class NettyRoutingFilterTests {
или включает Spring Cloud Eureka (на мой взгляд, путь к множеству зависимостей для неинтеграционного теста)

Код: Выделить всё

@ExtendWith( { SpringExtension.class } )
@SpringBootTest(classes = { MockConfigurer.class },
webEnvironment = WebEnvironment.RANDOM_PORT )
public class RoutingIT

Код: Выделить всё

@Configuration
public class MockConfigurer
{
private List services;

public MockConfigurer( List services)
{
this.services= services;
}

@Bean
public DiscoveryClient discoveryClient( )
{
  • "Интеграционный тест Spring не работает с Spring Boot 3 и Spring Cloud Gateway". Непонятно, как работает решение, в частности, откуда извлекается WebTestClient

Код: Выделить всё

@SpringBootTest(classes = MainApplication.class, webEnvironment = DEFINED_PORT)
public class HealthControllerTest {

@Autowired
private WebTestClient webTestClient;

@Test
public void health_shouldReturnHttp200() { this.webTestClient.get().uri(PATH).accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk();
}
}
Док
Я посетил страницу документации проекта, но не нашел конкретной главы о тестировании


Подробнее здесь: https://stackoverflow.com/questions/781 ... utelocator

Вернуться в «JAVA»