Search code examples
javaspringtestingspring-testspring-cloud-gateway

How to unit test spring's gateway?


My gateway will redirect traffic to many different services (under different domain names). how can i test the gateway's configuration? with only one service i can just setup the mock server (like httpbin) and test the response. with multiple services i'd prefer to avoid starting the whole docker network or changing the locak dns aliases. does spring offer any lightweight way of testing the gateway?


Solution

  • @apsisim provided a great idea to use web proxy. but the tool he suggests is not in any maven repo and has commercial license. what worked for me:

    run the gateway so it will use a proxy (u can be more fancy and find a free port):

    private const val proxyPort = 1080
    
    @SpringBootTest(
        properties = [
            //"logging.level.reactor.netty.http.server=debug",
            //"spring.cloud.gateway.httpserver.wiretap=true",
            //"spring.cloud.gateway.httpclient.wiretap=true",
            "spring.cloud.gateway.httpclient.proxy.host=localhost",
            "spring.cloud.gateway.httpclient.proxy.port=$proxyPort"
        ]
    )
    

    then use the mockwebserver as a proxy

    testImplementation("com.squareup.okhttp3:mockwebserver:4.2.1")
    testImplementation("com.squareup.okhttp3:okhttp:4.2.1")
    

    and then all your requests will go to your proxy. just remember that http protocol specifies that first request to new server requires tunneling via the proxy so when u do first request to the gateway, the gateway will send 2 requests to the proxy:

    testClient.get()
                .uri(path)
                .header("host", gatewayDns)
                .exchange()
    
    nextRequestFromGateway {
        method `should equal` "CONNECT"
        headers[HOST] `should equal` "$realUrlBehindGateway:80"
    }
    
    nextRequestFromGateway {
        path `should equal` "/api/v1/whatever"
        headers[HOST] `should equal` realUrlBehindGateway
    }
    
    ...
    fun nextRequestFromGateway(block : RecordedRequest.() -> Unit) {
        mockWebServer.takeRequest().apply (block)
    }