Skip to content

Commit e2fd2f2

Browse files
authored
Merge pull request #6 from braintrustdata/ark/config-builder
add a Builder to BraintrustConfig
2 parents 102e9d0 + a54c99b commit e2fd2f2

4 files changed

Lines changed: 139 additions & 1 deletion

File tree

src/main/java/dev/braintrust/config/BaseConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import java.util.Objects;
66
import javax.annotation.Nonnull;
77
import javax.annotation.Nullable;
8+
import lombok.EqualsAndHashCode;
89

10+
@EqualsAndHashCode
911
class BaseConfig {
1012
/** Sentinal used to set null in the env. Only used for testing. */
1113
static final String NULL_OVERRIDE = "BRAINTRUST_NULL_SENTINAL_" + System.currentTimeMillis();

src/main/java/dev/braintrust/config/BraintrustConfig.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,87 @@ public URI fetchProjectURI() {
9595
var orgAndProject = client.getProjectAndOrgInfo().orElseThrow();
9696
return BraintrustUtils.createProjectURI(appUrl(), orgAndProject);
9797
}
98+
99+
public static Builder builder() {
100+
return new Builder();
101+
}
102+
103+
public static class Builder {
104+
private final Map<String, String> envOverrides = new HashMap<>();
105+
106+
public Builder apiKey(String value) {
107+
envOverrides.put("BRAINTRUST_API_KEY", value);
108+
return this;
109+
}
110+
111+
public Builder apiUrl(String value) {
112+
envOverrides.put("BRAINTRUST_API_URL", value);
113+
return this;
114+
}
115+
116+
public Builder appUrl(String value) {
117+
envOverrides.put("BRAINTRUST_APP_URL", value);
118+
return this;
119+
}
120+
121+
public Builder tracesPath(String value) {
122+
envOverrides.put("BRAINTRUST_TRACES_PATH", value);
123+
return this;
124+
}
125+
126+
public Builder logsPath(String value) {
127+
envOverrides.put("BRAINTRUST_LOGS_PATH", value);
128+
return this;
129+
}
130+
131+
public Builder defaultProjectId(String value) {
132+
if (value != null) {
133+
envOverrides.put("BRAINTRUST_DEFAULT_PROJECT_ID", value);
134+
} else {
135+
envOverrides.put("BRAINTRUST_DEFAULT_PROJECT_ID", NULL_OVERRIDE);
136+
}
137+
return this;
138+
}
139+
140+
public Builder defaultProjectName(String value) {
141+
if (value != null) {
142+
envOverrides.put("BRAINTRUST_DEFAULT_PROJECT_NAME", value);
143+
} else {
144+
envOverrides.put("BRAINTRUST_DEFAULT_PROJECT_NAME", NULL_OVERRIDE);
145+
}
146+
return this;
147+
}
148+
149+
public Builder enableTraceConsoleLog(boolean value) {
150+
envOverrides.put("BRAINTRUST_ENABLE_TRACE_CONSOLE_LOG", String.valueOf(value));
151+
return this;
152+
}
153+
154+
public Builder debug(boolean value) {
155+
envOverrides.put("BRAINTRUST_DEBUG", String.valueOf(value));
156+
return this;
157+
}
158+
159+
public Builder requestTimeout(Duration value) {
160+
envOverrides.put("BRAINTRUST_REQUEST_TIMEOUT", String.valueOf(value.getSeconds()));
161+
return this;
162+
}
163+
164+
// hiding visibility. only used for testing
165+
Builder experimentalOtelLogs(boolean value) {
166+
envOverrides.put("BRAINTRUST_X_OTEL_LOGS", String.valueOf(value));
167+
return this;
168+
}
169+
170+
// hiding visibility. only used for testing
171+
Builder exportSpansInMemoryForUnitTest(boolean value) {
172+
envOverrides.put(
173+
"BRAINTRUST_JAVA_EXPORT_SPANS_IN_MEMORY_FOR_UNIT_TEST", String.valueOf(value));
174+
return this;
175+
}
176+
177+
public BraintrustConfig build() {
178+
return new BraintrustConfig(envOverrides);
179+
}
180+
}
98181
}

src/test/java/dev/braintrust/config/BaseConfigTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ void testIntegrationWithAllTypes() {
182182
assertEquals(2.71828, config.getConfig("DOUBLE_VAR", 0.0), 0.00001);
183183
}
184184

185+
@Test
186+
void testEquals() {
187+
var cfg1 = new TestConfig(Map.of("FOO", "bar"));
188+
var cfg2 = new TestConfig(Map.of("FOO", "bar"));
189+
var cfg3 = new TestConfig(Map.of("FOO", "baz"));
190+
assertEquals(cfg1, cfg2);
191+
assertNotEquals(cfg1, cfg3);
192+
}
193+
185194
static class TestConfig extends BaseConfig {
186195
TestConfig(Map<String, String> envOverrides) {
187196
super(envOverrides);

src/test/java/dev/braintrust/config/BraintrustConfigTest.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package dev.braintrust.config;
22

3-
import static org.junit.jupiter.api.Assertions.assertEquals;
3+
import static org.junit.jupiter.api.Assertions.*;
44

5+
import java.lang.reflect.Field;
6+
import java.lang.reflect.Method;
7+
import java.util.Arrays;
8+
import java.util.List;
9+
import java.util.Set;
10+
import java.util.stream.Collectors;
511
import org.junit.jupiter.api.Test;
612

713
class BraintrustConfigTest {
@@ -28,4 +34,42 @@ void parentUsesProjectId() {
2834
"project_id:" + defaultConfig.defaultProjectId().orElseThrow(),
2935
defaultConfig.getBraintrustParentValue().orElseThrow());
3036
}
37+
38+
@Test
39+
public void testBuilderEqualsEnv() {
40+
var fromEnv =
41+
BraintrustConfig.of(
42+
"BRAINTRUST_API_KEY", "testkey",
43+
"BRAINTRUST_DEFAULT_PROJECT_ID", "unit-test");
44+
var fromBuilder =
45+
BraintrustConfig.builder().apiKey("testkey").defaultProjectId("unit-test").build();
46+
var otherBuilder =
47+
BraintrustConfig.builder().apiKey("otherkey").defaultProjectId("unit-test").build();
48+
assertEquals(fromEnv, fromBuilder);
49+
assertNotEquals(fromEnv, otherBuilder);
50+
}
51+
52+
@Test
53+
public void testBuilderHasMethodForEveryField() {
54+
List<String> fieldsToSkip = List.of("envOverrides");
55+
// Get all fields from BraintrustConfig
56+
Field[] configFields = BraintrustConfig.class.getDeclaredFields();
57+
58+
// Get all methods from Builder
59+
Method[] builderMethods = BraintrustConfig.Builder.class.getDeclaredMethods();
60+
Set<String> builderMethodNames =
61+
Arrays.stream(builderMethods).map(Method::getName).collect(Collectors.toSet());
62+
63+
// For each field, verify there's a corresponding builder method
64+
for (Field field : configFields) {
65+
String configFieldName = field.getName();
66+
// Skip internal fields
67+
if (fieldsToSkip.contains(configFieldName)) {
68+
continue;
69+
}
70+
assertTrue(
71+
builderMethodNames.contains(configFieldName),
72+
"Builder is missing method for field: " + configFieldName);
73+
}
74+
}
3175
}

0 commit comments

Comments
 (0)