Search code examples
springspring-bootspring-boot-actuatormicrometer-tracing

How to test traceId propagation with WebTestClient + Micrometer Tracer?


After migration to Spring Boot 3 and refactor from Sleuth to Micrometer, I am no more able to test traceId propagation with WebTestClient + Tracer.

My test here, is to have a simple @RestController where I expect the traceId being propagated through the Tracer :

@RestController
class MyTraceIdController(@Autowired private val tracer: Tracer) {


    @GetMapping("/trace")
    fun info(): ResponseEntity<String> {

        val traceKey = "x-b3-traceid"

        // Using tracer the traceId is retrieved at runtime but not during test
        val responseHeaders = HttpHeaders()
        responseHeaders.set(traceKey, tracer.currentSpan()?.context()?.traceId().toString())

        return ResponseEntity
            .ok()
            .headers(responseHeaders)
            .body("OK")
    }

}

And the goal is to test it thanks to the WebTestClient :

@AutoConfigureWebTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class MyTraceIdTests(@Autowired private val webTestClient: WebTestClient) {

    @Test
    fun `Assert info endpoint works as expected with webTestClient`() {

        val traceKey = "x-b3-traceid"
        val traceValue = "463ac35c9f6413ad48485a3953bb6124"

        val spanKey = "x-b3-spanid"
        val spanValue = "a2fb4a1d1a96d312"

        webTestClient.get()
            .uri("http://localhost:9080/trace")
            .header(traceKey, traceValue)
            .header(spanKey, spanValue)
            .exchange()
            .expectStatus().isOk
            .expectHeader().valueEquals(traceKey, traceValue)
            .expectBody<String>().isEqualTo("OK")
    }

}

With Sleuth, when running tests, the BraveTracer that was injected did perfectly the job to propagate the traceId.

With Micrometer, I am not able anymore to have one correct tracer injected to do the job.

To test the case, I have created the following sample :

https://github.com/bvoglevette/trace-id-sample

Two behaviors are observable :

  • At runtime, executing bootRun + curl on the endpoint, the BraveAutoconfiguration is used and one correct BraveTracer is injected => It works as expected
  • At test time, I am not able to get one correct BraveTracer bean injected => The traceId is always null

The different approaches I have tried without success

  • To use SimpleTracer()
  • To implement my own Tracer bean, following Micrometer documentation
  • To use the BraveAutoconfiguration in my test or to instanciate beans based on it

None of these implementations have been able to produce one bean where the traceId is propagated.

I expect more to find a way to simply inject a working bean coming from BraveAutoconfiguration. What Am I missing ? Should I do my test diffently ?


Solution

  • You need to add @AutoConfigureObservability on your test class. By default observability is disabled in tests.