Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '11', '17', '21' ]
java: [ '17', '21' ]

steps:
- uses: actions/checkout@v4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public static <REQ, RESP> RESP traceMessage(
RequestExtractor<REQ> requestExtractor,
ResponseExtractor<RESP> responseExtractor,
Supplier<RESP> executeRequest) {
// Get tracer lazily to ensure test setup is complete
var tracer = BraintrustTracing.getTracer();
var requestDetails = requestExtractor.extract(request);

Expand Down Expand Up @@ -75,6 +76,7 @@ public static <REQ, RESP> CompletableFuture<RESP> traceMessageAsync(
RequestExtractor<REQ> requestExtractor,
ResponseExtractor<RESP> responseExtractor,
Supplier<CompletableFuture<RESP>> executeRequest) {
// Get tracer lazily to ensure test setup is complete
var tracer = BraintrustTracing.getTracer();
var requestDetails = requestExtractor.extract(request);

Expand Down Expand Up @@ -134,6 +136,7 @@ public static <REQ, STREAM> STREAM traceStreamingMessage(
RequestExtractor<REQ> requestExtractor,
Supplier<STREAM> executeRequest,
StreamWrapper<STREAM> streamWrapper) {
// Get tracer lazily to ensure test setup is complete
var tracer = BraintrustTracing.getTracer();
var requestDetails = requestExtractor.extract(request);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public static <REQ, RESP> RESP traceCompletion(
RequestExtractor<REQ> requestExtractor,
ResponseExtractor<RESP> responseExtractor,
Supplier<RESP> executeRequest) {
// Get tracer lazily to ensure test setup is complete
var tracer = BraintrustTracing.getTracer();
var requestDetails = requestExtractor.extract(request);

Expand Down Expand Up @@ -100,6 +101,7 @@ public static <REQ, STREAM, RESP> STREAM traceStreamingCompletion(
RequestExtractor<REQ> requestExtractor,
Supplier<STREAM> executeRequest,
StreamWrapper<STREAM, RESP> streamWrapper) {
// Get tracer lazily to ensure test setup is complete
var tracer = BraintrustTracing.getTracer();
var requestDetails = requestExtractor.extract(request);

Expand Down
4 changes: 2 additions & 2 deletions src/test/java/dev/braintrust/api/BraintrustApiClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ void testCreateProject() throws Exception {
argThat(
request -> {
assertThat(request.uri().toString())
.isEqualTo("https://api.test.dev/projects");
.isEqualTo("https://api.test.dev/v1/project");
assertThat(request.method()).isEqualTo("POST");
assertThat(request.headers().firstValue("Authorization"))
.hasValue("Bearer test-api-key");
Expand Down Expand Up @@ -229,7 +229,7 @@ void testInsertDatasetEvents() throws Exception {
request -> {
assertThat(request.uri().toString())
.isEqualTo(
"https://api.test.dev/datasets/dataset-123/insert");
"https://api.test.dev/v1/dataset/dataset-123/insert");
assertThat(request.method()).isEqualTo("POST");
return true;
}),
Expand Down
35 changes: 13 additions & 22 deletions src/test/java/dev/braintrust/eval/EvaluationIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,11 @@ void setUp() {
.build();

// Set up tracing with in-memory exporter
var braintrustProcessor =
new BraintrustSpanProcessor(config, SimpleSpanProcessor.create(spanExporter));

var tracerProvider =
SdkTracerProvider.builder()
.addSpanProcessor(
new BraintrustSpanProcessor.Builder(config)
.withExporter(spanExporter)
.build())
.addSpanProcessor(SimpleSpanProcessor.create(spanExporter))
.build();
SdkTracerProvider.builder().addSpanProcessor(braintrustProcessor).build();

GlobalOpenTelemetry.resetForTest();
GlobalOpenTelemetry.set(
Expand Down Expand Up @@ -84,20 +81,17 @@ void testEvaluationWithTracing() {

// Find evaluation span
var evalSpan =
spans.stream()
.filter(s -> s.getName().equals("evaluation"))
.findFirst()
.orElseThrow();
spans.stream().filter(s -> s.getName().equals("eval")).findFirst().orElseThrow();

assertThat(
evalSpan.getAttributes()
.get(
io.opentelemetry.api.common.AttributeKey.stringKey(
"evaluation.name")))
.isEqualTo("traced-evaluation");
"braintrust.span_attributes")))
.isEqualTo("{\"type\":\"eval\"}");

// Verify task spans
var taskSpans = spans.stream().filter(s -> s.getName().equals("evaluation.task")).toList();
var taskSpans = spans.stream().filter(s -> s.getName().equals("task")).toList();
assertThat(taskSpans).hasSize(3);
}

Expand Down Expand Up @@ -128,10 +122,7 @@ void testEvaluationWithExperimentContext() {
// Verify experiment parent was set
var spans = spanExporter.getFinishedSpanItems();
var evalSpan =
spans.stream()
.filter(s -> s.getName().equals("evaluation"))
.findFirst()
.orElseThrow();
spans.stream().filter(s -> s.getName().equals("eval")).findFirst().orElseThrow();

assertThat(evalSpan.getAttributes().get(BraintrustSpanProcessor.PARENT_EXPERIMENT_ID))
.isEqualTo("exp-123");
Expand Down Expand Up @@ -175,7 +166,7 @@ void testParallelEvaluationWithMetrics() {

// Verify parallel execution via span timing
var spans = spanExporter.getFinishedSpanItems();
var taskSpans = spans.stream().filter(s -> s.getName().equals("evaluation.task")).toList();
var taskSpans = spans.stream().filter(s -> s.getName().equals("task")).toList();

assertThat(taskSpans).hasSize(100);

Expand Down Expand Up @@ -238,7 +229,7 @@ record TestCase(int number, boolean shouldFail) {}
var spans = spanExporter.getFinishedSpanItems();
var errorSpans =
spans.stream()
.filter(s -> s.getName().equals("evaluation.task"))
.filter(s -> s.getName().equals("task"))
.filter(
s ->
s.getStatus().getStatusCode()
Expand Down Expand Up @@ -310,9 +301,9 @@ record QA(String question, String expectedAnswer) {}

// Verify scores are recorded in spans
var spans = spanExporter.getFinishedSpanItems();
var taskSpans = spans.stream().filter(s -> s.getName().equals("evaluation.task")).toList();
var evalSpans = spans.stream().filter(s -> s.getName().equals("eval")).toList();

taskSpans.forEach(
evalSpans.forEach(
span -> {
var attrs = span.getAttributes();
assertThat(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,33 +206,27 @@ void testTraceStreamingMessage() {
// Then
assertThat(result).isEqualTo(stream);

// Verify initial span
// Simulate streaming chunks
capturedOnChunk.get().accept(new TestChunk("chunk1"));
capturedOnChunk.get().accept(new TestChunk("chunk2"));
capturedOnChunk.get().accept(new TestChunk("chunk3"));

// Complete stream
capturedOnComplete.get().run();

// Verify span after completion
var spans = otelTesting.getSpans();
assertThat(spans).hasSize(1);

var span = spans.get(0);
assertThat(span.getName()).isEqualTo("anthropic.messages.stream");
assertThat(span.hasEnded()).isFalse();
assertThat(span.hasEnded()).isTrue();
assertThat(
span.getAttributes()
.get(
io.opentelemetry.api.common.AttributeKey.booleanKey(
"anthropic.stream")))
.isTrue();

// Simulate streaming chunks
capturedOnChunk.get().accept(new TestChunk("chunk1"));
capturedOnChunk.get().accept(new TestChunk("chunk2"));
capturedOnChunk.get().accept(new TestChunk("chunk3"));

// Complete stream
capturedOnComplete.get().run();

// Re-fetch spans after completion
spans = otelTesting.getSpans();
span = spans.get(0);

assertThat(span.hasEnded()).isTrue();
assertThat(span.getStatus().getStatusCode()).isEqualTo(StatusCode.OK);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,31 +146,22 @@ void testTraceStreamingCompletion() {
// Then
assertThat(result).isEqualTo(stream);

// Force flush to ensure spans are available
// Note: OpenTelemetryExtension handles this automatically
// Simulate stream completion to close the span
capturedOnComplete.get().accept(new OpenAIInterceptor.Usage(200, 100, 300));

// Verify initial span
// Verify span after completion
var spans = otelTesting.getSpans();
assertThat(spans).hasSize(1);

var span = spans.get(0);
assertThat(span.getName()).isEqualTo("openai.chat.completion.stream");
assertThat(span.hasEnded()).isFalse();
assertThat(span.hasEnded()).isTrue();
assertThat(
span.getAttributes()
.get(
io.opentelemetry.api.common.AttributeKey.booleanKey(
"openai.stream")))
.isTrue();

// Simulate stream completion
capturedOnComplete.get().accept(new OpenAIInterceptor.Usage(200, 100, 300));

// Re-fetch spans after completion
spans = otelTesting.getSpans();
span = spans.get(0);

assertThat(span.hasEnded()).isTrue();
assertThat(span.getStatus().getStatusCode()).isEqualTo(StatusCode.OK);
assertThat(span.getAttributes().get(BraintrustSpanProcessor.USAGE_PROMPT_TOKENS))
.isEqualTo(200L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.atLeastOnce;

import dev.braintrust.config.BraintrustConfig;
import io.opentelemetry.context.Context;
Expand Down Expand Up @@ -41,47 +40,44 @@ void setUp() {
void testDefaultProjectIdIsAdded() {
// Given
var span = mock(ReadWriteSpan.class);
when(span.getAttribute(BraintrustSpanProcessor.PARENT_PROJECT_ID)).thenReturn(null);
when(span.getAttribute(BraintrustSpanProcessor.PARENT_EXPERIMENT_ID)).thenReturn(null);
when(span.getAttribute(BraintrustSpanProcessor.PARENT)).thenReturn(null);

// When
processor.onStart(Context.root(), span);

// Then
verify(span).setAttribute(BraintrustSpanProcessor.PARENT_PROJECT_ID, "default-project");
verify(span).setAttribute(BraintrustSpanProcessor.PARENT_TYPE, "project");
verify(span).setAttribute(BraintrustSpanProcessor.PARENT, "project_id:default-project");
verify(mockDelegate).onStart(any(), eq(span));
}

@Test
void testProjectIdFromContext() {
// Given
var span = mock(ReadWriteSpan.class);
when(span.getAttribute(BraintrustSpanProcessor.PARENT)).thenReturn(null);
var context =
BraintrustContext.forProject("context-project").storeInContext(Context.root());

// When
processor.onStart(context, span);

// Then
verify(span).setAttribute(BraintrustSpanProcessor.PARENT_PROJECT_ID, "context-project");
// Parent type might be set multiple times due to both project and parent type being set
verify(span, atLeastOnce()).setAttribute(BraintrustSpanProcessor.PARENT_TYPE, "project");
verify(span).setAttribute(BraintrustSpanProcessor.PARENT, "project_id:context-project");
}

@Test
void testExperimentIdFromContext() {
// Given
var span = mock(ReadWriteSpan.class);
when(span.getAttribute(BraintrustSpanProcessor.PARENT)).thenReturn(null);
var context =
BraintrustContext.forExperiment("experiment-123").storeInContext(Context.root());

// When
processor.onStart(context, span);

// Then
verify(span).setAttribute(BraintrustSpanProcessor.PARENT_EXPERIMENT_ID, "experiment-123");
verify(span).setAttribute(BraintrustSpanProcessor.PARENT_TYPE, "experiment");
verify(span).setAttribute(BraintrustSpanProcessor.PARENT, "experiment_id:experiment-123");
}

@Test
Expand Down
12 changes: 4 additions & 8 deletions src/test/java/dev/braintrust/trace/BraintrustTracingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,8 @@ void testSpanUtilsSetParentProject() {
assertThat(spans).hasSize(1);

var spanData = spans.get(0);
assertThat(spanData.getAttributes().get(BraintrustSpanProcessor.PARENT_PROJECT_ID))
.isEqualTo("project-123");
assertThat(spanData.getAttributes().get(BraintrustSpanProcessor.PARENT_TYPE))
.isEqualTo("project");
assertThat(spanData.getAttributes().get(BraintrustSpanProcessor.PARENT))
.isEqualTo("project_id:project-123");
}

@Test
Expand All @@ -200,10 +198,8 @@ void testSpanUtilsSetParentExperiment() {
assertThat(spans).hasSize(1);

var spanData = spans.get(0);
assertThat(spanData.getAttributes().get(BraintrustSpanProcessor.PARENT_EXPERIMENT_ID))
.isEqualTo("exp-456");
assertThat(spanData.getAttributes().get(BraintrustSpanProcessor.PARENT_TYPE))
.isEqualTo("experiment");
assertThat(spanData.getAttributes().get(BraintrustSpanProcessor.PARENT))
.isEqualTo("experiment_id:exp-456");
}

@Test
Expand Down