This package contains comprehensive tests for OpenTelemetry distributed tracing functionality.
We use a three-tier testing strategy to verify that distributed tracing works correctly:
DistributedTracingTest.javaPurpose: Fast unit tests using in-memory span exporter
What it tests:
@Observed methodsHow it works:
InMemorySpanExporter to capture spans without external infrastructureRun with:
./gradlew test --tests DistributedTracingTest
OtlpExportIntegrationTest.javaPurpose: End-to-end integration test with real OTLP collector
What it tests:
How it works:
Run with:
./gradlew test --tests OtlpExportIntegrationTest
Note: This test is slower (30+ seconds) due to:
ObservabilityTestConfiguration.javaTest configuration that provides:
InMemorySpanExporter bean for capturing spansSdkTracerProvider configured to use in-memory exporterLgtmAssertions.javaHelper for querying LGTM stack (Tempo, Prometheus, Loki):
LgtmAssertions lgtm = new LgtmAssertions(lgtmContainer, objectMapper); // Fetch trace by ID Optional<JsonNode> trace = lgtm.getTraceById(traceId); // Search traces with TraceQL Optional<JsonNode> traces = lgtm.searchTraces("{.service.name=\"solr-mcp-server\"}", 10); // Query Prometheus metrics Optional<JsonNode> metrics = lgtm.queryPrometheus("http_server_requests_seconds_count");
TraceAssertions.javaFluent assertion utilities for trace verification:
// Assert span exists TraceAssertions.assertSpanExists(spans, "SearchService.search"); // Assert span has attribute TraceAssertions.assertSpanHasAttribute(spans, "SearchService", "collection", "test"); // Assert span count TraceAssertions.assertSpanCount(spans, 3); // Assert span kind TraceAssertions.assertSpanKind(spans, "SearchService", SpanKind.INTERNAL); // Find specific span SpanData span = TraceAssertions.findSpan(spans, "SearchService");
# Run all observability tests ./gradlew test --tests "org.apache.solr.mcp.server.observability.*" # Run with coverage ./gradlew test jacocoTestReport --tests "org.apache.solr.mcp.server.observability.*"
For local development, you can verify tracing works by:
Start LGTM stack:
docker compose up -d lgtm
Run the application in HTTP mode:
PROFILES=http ./gradlew bootRun
Execute some operations (via MCP client or HTTP API):
Open Grafana: http://localhost:3000
solr-mcp-serverAll service methods annotated with @Observed automatically create spans:
Spring Boot also automatically instruments:
The unit tests (DistributedTracingTest) are fast and suitable for CI:
# GitHub Actions example - name: Run observability tests run: ./gradlew test --tests "DistributedTracingTest"
The integration tests (OtlpExportIntegrationTest) can be run:
@Observed methodsProblem: InMemorySpanExporter returns empty list
Solutions:
@Observed annotation is present on methodmanagement.observations.annotations.enabled=truespring-boot-starter-aspectj dependency)await() with sufficient timeout (spans are async)Problem: OtlpExportIntegrationTest times out waiting for traces
Solutions:
await().atMost(60, TimeUnit.SECONDS)docker ps | grep lgtmdocker logs solr-mcp-lgtm-1Problem: Grafana/Tempo shows no traces
Solutions:
docker compose pshttp://localhost:4318/v1/tracesspring.opentelemetry.tracing.export.otlp.endpoint is setmanagement.tracing.sampling.probability=1.0 (100% sampling)@Test void shouldCreateSpanForMyOperation() throws Exception { // Given: Initial state spanExporter.reset(); // When: Execute operation myService.doSomething(); // Then: Verify span was created await() .atMost(5, TimeUnit.SECONDS) .untilAsserted(() -> { List<SpanData> spans = spanExporter.getFinishedSpanItems(); TraceAssertions.assertSpanExists(spans, "MyService.doSomething"); TraceAssertions.assertSpanHasAttribute(spans, "MyService", "operation", "doSomething"); }); }