spring-cloud / spring-cloud-gateway

An API Gateway built on Spring Framework and Spring Boot providing routing and more.
http://cloud.spring.io
Apache License 2.0
4.53k stars 3.32k forks source link

Filter/Predicate validation message are not returned when `management.server.port` is set for actuator #2466

Open abelsromero opened 2 years ago

abelsromero commented 2 years ago

Describe the bug The feature added in https://github.com/spring-cloud/spring-cloud-gateway/commit/f6bfd6e474fbbc0f627d9bd6bc6c1c80c7f393c9 does not work when user sets a custom management port with management.server.port.

Sample

The test below copied from current test https://github.com/spring-cloud/spring-cloud-gateway/blob/84ddb3ed74ba1a4543cf25dd95cd914c68a536da/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java#L182 when run in SCG repo (main branch) fails with

java.lang.AssertionError: No value at JSON path "$.message"
  ...
Caused by: java.lang.IllegalArgumentException: json can not be null or empty

The only difference with original test is the use of management.server.port=0 to change the port and removal of unnecessary code.

package org.springframework.cloud.gateway.actuate;

import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

import java.net.URI;
import java.util.Collections;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.test.PermitAllSecurityConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.BodyInserters;

@RunWith(SpringRunner.class)
@SpringBootTest(properties = { "management.endpoints.web.exposure.include=*",
        "spring.cloud.gateway.actuator.verbose.enabled=true",
        "management.server.port=0"
        }, webEnvironment = RANDOM_PORT)
public class GatewayControllerEndpointWithCustomManagementPortTests {

    @Autowired
    WebTestClient testClient;

    @LocalServerPort
    int port;

    @LocalManagementPort
    int managementPort;

    @Test
    public void testPostRouteWithNotExistingPredicate() {

        RouteDefinition testRouteDefinition = new RouteDefinition();
        testRouteDefinition.setUri(URI.create("http://example.org"));

        PredicateDefinition predicateDefinition = new PredicateDefinition("NotExistingPredicate=test-config");
        testRouteDefinition.setPredicates(Collections.singletonList(predicateDefinition));

        testClient.post().uri("http://localhost:" + managementPort + "/actuator/gateway/routes/test-route")
                .accept(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(testRouteDefinition)).exchange()
                .expectStatus().isBadRequest().expectBody().jsonPath("$.message")
                .isEqualTo("Invalid PredicateDefinition: [NotExistingPredicate]");
    }

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @Import(PermitAllSecurityConfiguration.class)
    static class TestConfig {
    }

}
abelsromero commented 2 years ago

From what we've seen, it seems WebExceptionHandler are loaded in different order running WebFluxResponseStatusExceptionHandler first witch automatically responds.

Without management port

  1. ExceptionHandlingWebHander
  2. DefaultErrorWebExceptionHandler
  3. WebFluxResponseStatusExceptionHandler

With it

  1. ExceptionHandlingWebHander
  2. WebFluxResponseStatusExceptionHandler
  3. DefaultErrorWebExceptionHandler