Search code examples
javaspring-bootspring-boot-testspring-webtestclient

WebTestClient on HTTPS with SpringBootTest random_port


I have a rest service for which I needed to implement TLSv1.3 over HTTPS (HTTP is prohibited at my place for this app). Now the tests are failing because WebTestClient is making calls using http protocol over https. I know I could build WebTestClient myself, but to make things more interesting these tests are using RANDOM_PORT because the CI jobs are running on a single jenkins node that's shared across different teams (I cannot remove it safely).

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "spring.main.allow-bean-definition-overriding=true")
@ContextConfiguration(classes = TestWebClientConfiguration.class)  // contains beans to connect to mocked downstream services
@TestMethodOrder(MethodOrdeded.OrderAnnotation.class)
@DirtiesContext
@AutoConfigureWebTestClient
@ActiveProfiles(value = {"test"})
public class HealthCheckTests {
    @Autowired
    private WebTestClient webTestClient;
    ...
}

Based on the application logs I can see that webTestClient is making calls to my service like:

GET http://localhost:19654/health-check

which was working fine, but now it should be https. Can I configure WebTestClient to use HTTPS while using AutoConfigureWebTestClient, alternatively how can I configure WebTestClient towards to RANDOM_PORT that spring sets.

@Update Here's what I have tried already:

private WebTestClient webTestClient;

@PostConstruct
void init() throws SSLException {
    // var sslContext = SSLContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build;
    // var httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
    webTestClient = WebTestClient.bindToServer().baseUrl("https://localhost:<fix_port>").build()
}

This works to some degree. The requests are sent over HTTPS the issues are getting the port from WebEnvironment, and obviously the incorrect certificates. While WebClient has clientConnector where httpClient can be configured, I cannot seem to find the equivalent to this for WebTestClient.

@Update2: I managed to configure the SSLContext with the WebTestClient, the only issue that remains is that I can only do it if I'm hardcoding the port.

@PostConstruct
void init() throws SSLException {
    var sslContext = SSLContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build;
    var httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
    webTestClient = WebTestClient.bindToServer(new ReactorClientHttpConnector(httpClient)).baseUrl("https://localhost:<fixed-port>").build();
}

Solution

  • Not an elegant solution, but I managed to get it working, but not with @AuthConfigureWebTestClient. The final solution was the below:

    @LocalServerPort
    private int port;
    
    private WebTestClient webTestClient;
    
    @PostConstruct
    void init() throws SSLException {
        var sslContext = SSLContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build;
        var httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
        webTestClient = WebTestClient.bindToServer(new ReactorClientHttpConnector(httpClient)).baseUrl("https://localhost:%d".formatted(port)).build();
    }