Search code examples
javaspringjunitspring-cloud-sleuth

BaggageField updateValue method returns false in jUnit tests


EDIT: One problem was that Tracing.current() was null. I fixed this with the new @BeforeEach instead of the old @BeforeTestMethod:

Tracer tracer;

@BeforeEach
void init() {
    tracer = Tracing.newBuilder().build().tracer();
    TraceContext ctx = TraceContext.newBuilder().traceId(17).spanId(17).build();
    Span span = tracer.toSpan(ctx);
    tracer.withSpanInScope(span);
}

Yet, updateValue still doesn't work as there are no extras in the context, so nothing to update...


Following the ideas like in those answers, I'm trying to use BaggageFields in one of my tests. All the objects are not null, but updateValue returns false and the test fails with BaggageTest.baggageTest:40 expected: <hello> but was: <null>. As said, I have no idea why the updateValue method is not working.

import static org.junit.jupiter.api.Assertions.assertEquals;

import brave.baggage.BaggageField;
import brave.baggage.CorrelationScopeConfig;
import brave.context.slf4j.MDCScopeDecorator;
import brave.propagation.CurrentTraceContext;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.ScopedSpan;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.event.annotation.BeforeTestMethod;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@Slf4j
@ExtendWith(SpringExtension.class)
@ContextConfiguration
public class BaggageTest {

    @Autowired
    ApplicationContext context;
    
    @BeforeTestMethod
    void init() {
        Tracer tracer = context.getBean(Tracer.class);
        ScopedSpan span = tracer.startScopedSpan("test");
    }

    @Test
    void baggageTest() {
        BaggageField fooBar = context.getBean("fooBar", BaggageField.class);
        log.info("updateValue {}", fooBar.updateValue("hello"));
        assertEquals("hello", fooBar.getValue());
    }

    @Configuration
    static class Config {

        private BaggageField findOrCreate(String name) {
            BaggageField field = BaggageField.getByName(name);
            if (field == null) {
                field = BaggageField.create(name);
            }
            return field;
        }

        @Bean("fooBar")
        BaggageField fooBar() {
            return findOrCreate("fooBar");
        }

        @Bean
        CurrentTraceContext.ScopeDecorator mdcScopeDecorator() {
            return MDCScopeDecorator.newBuilder()
                .clear()
                .add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(fooBar())
                    .flushOnUpdate()
                    .build())
                .build();
        }
    }
}

Solution

  • My solution is to manually build the TraceContext, using the following snippet, being careful that BaggageFields is brave.internal.baggage.BaggageFields.

    @Autowired
    BaggageField field;
    
    Tracer tracer;
    
    @BeforeEach
    void init() {
        tracer = Tracing.newBuilder().build().tracer();
        ArrayList<BaggageField> list = new ArrayList<>();
        list.add(field);
        TraceContext ctx = TraceContext.newBuilder()
            .addExtra(BaggageFields.newFactory(list,2).create())
            .traceId(17).spanId(17).build();
        Span span = tracer.toSpan(ctx);
        tracer.withSpanInScope(span);
    }