test(observability): isolate raw OTel contexts and assert trace coexistence

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
XiaoSeS 2026-11-05 23:24:35 +08:00
parent a4d2bbe462
commit 89066c6988
7 changed files with 68 additions and 1 deletions

View file

@ -175,7 +175,22 @@
<execution>
<id>default-test</id>
<configuration>
<excludedGroups>process-global-diagnostics</excludedGroups>
<excludedGroups>process-global-diagnostics,process-global-otel-context</excludedGroups>
</configuration>
</execution>
<!-- Raw OTel contexts initialize JVM-global ContextStorage before Boot can
register its MDC wrapper. Each tagged class gets a fresh process. -->
<execution>
<id>isolated-otel-context</id>
<goals><goal>test</goal></goals>
<configuration>
<groups>process-global-otel-context</groups>
<includes>
<include>**/BusinessLogs*Test.java</include>
</includes>
<failIfNoSpecifiedTests>false</failIfNoSpecifiedTests>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</execution>
<execution>

View file

@ -32,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/** Actual production configuration sends protobuf over HTTP to a pinned real Collector/file sink. */
@Testcontainers
@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsCollectorTest {
@Container
static final GenericContainer<?> COLLECTOR = new GenericContainer<>("otel/opentelemetry-collector-contrib:0.111.0")

View file

@ -21,6 +21,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsHttpTest {
@Test
void truncatedErrorBodyCannotPermanentlyExhaustAdmission() throws Exception {

View file

@ -20,6 +20,7 @@ import org.junit.jupiter.params.provider.ValueSource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsPipelineTest {
@ParameterizedTest
@ValueSource(booleans = {true, false})

View file

@ -64,6 +64,7 @@ import static org.mockito.Mockito.when;
SkillDownloadService.class, SkillSlugResolutionService.class, ReviewService.class, PromotionService.class,
ReviewPermissionChecker.class, BusinessLogsProducerPostgresTest.Configuration.class})
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsProducerPostgresTest {
@Container
static final PostgreSQLContainer<?> POSTGRES = new PostgreSQLContainer<>("postgres:16-alpine")

View file

@ -0,0 +1,47 @@
package com.iflytek.skillhub.observability.business;
import com.iflytek.skillhub.observability.tracing.SkillHubTracingConfiguration;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.micrometer.tracing.Tracer;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.slf4j.MDC;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.assertThat;
/** Production configurations must coexist in the same startup, before any raw test context. */
@Tag("process-global-otel-context")
class BusinessLogsTracingCoexistenceTest {
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@Import({SkillHubTracingConfiguration.class, BusinessLogsConfiguration.class})
static class Application {}
@Test
void enablingBusinessLogsPreservesTraceAndSpanCorrelation() {
new ApplicationContextRunner().withUserConfiguration(Application.class)
.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)
.withPropertyValues("spring.flyway.enabled=false", "spring.jpa.hibernate.ddl-auto=none",
"skillhub.observability.tracing-mode=otel-sdk",
"management.tracing.sampling.probability=1",
"skillhub.observability.business-logs.enabled=true",
"skillhub.observability.business-logs.endpoint=http://127.0.0.1:4318/v1/logs")
.run(context -> {
assertThat(context).hasNotFailed();
assertThat(context).hasSingleBean(BusinessLogsPipeline.class);
Tracer tracer = context.getBean(Tracer.class);
var span = tracer.nextSpan().name("business-logs-coexistence").start();
try (var ignored = tracer.withSpan(span)) {
assertThat(MDC.get("traceId")).isEqualTo(span.context().traceId()).hasSize(32);
assertThat(MDC.get("spanId")).isEqualTo(span.context().spanId()).hasSize(16);
} finally {
span.end();
MDC.clear();
}
});
}
}

View file

@ -47,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.*;
@Testcontainers
@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsTransactionTest {
@Container
static final PostgreSQLContainer<?> POSTGRES = new PostgreSQLContainer<>("postgres:16-alpine")