Skip to content

Commit c053289

Browse files
eddumelendeztzolov
authored andcommitted
Support Chroma's CHROMA_SERVER_AUTH_CREDENTIALS env var from version 0.4.x
Currently, Docker Compose and Testcontainers support `CHROMA_SERVER_AUTHN_CREDENTIALS`, which is provided by Chroma 0.5.x. Previous versions use `CHROMA_SERVER_AUTH_CREDENTIALS` instead.
1 parent 865f62a commit c053289

File tree

4 files changed

+127
-3
lines changed

4 files changed

+127
-3
lines changed

spring-ai-spring-boot-docker-compose/src/main/java/org/springframework/ai/docker/compose/service/connection/chroma/ChromaEnvironment.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,20 @@
1919

2020
class ChromaEnvironment {
2121

22+
// Chroma version <= 0.4.x
23+
private static final String CHROMA_SERVER_AUTH_CREDENTIALS = "CHROMA_SERVER_AUTH_CREDENTIALS";
24+
25+
// Chroma version >= 0.5.x
26+
private static final String CHROMA_SERVER_AUTHN_CREDENTIALS = "CHROMA_SERVER_AUTHN_CREDENTIALS";
27+
2228
private final String keyToken;
2329

2430
ChromaEnvironment(Map<String, String> env) {
25-
this.keyToken = env.get("CHROMA_SERVER_AUTHN_CREDENTIALS");
31+
if (env.containsKey(CHROMA_SERVER_AUTH_CREDENTIALS)) {
32+
this.keyToken = env.get(CHROMA_SERVER_AUTH_CREDENTIALS);
33+
return;
34+
}
35+
this.keyToken = env.get(CHROMA_SERVER_AUTHN_CREDENTIALS);
2636
}
2737

2838
public String getKeyToken() {

spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/ai/docker/compose/service/connection/chroma/ChromaEnvironmentTests.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@ void getKeyTokenWhenNoCredential() {
3131
}
3232

3333
@Test
34-
void getKeyTokenWhenHasCredential() {
34+
void getKeyTokenFromAuthCredentialsWhenHasCredential() {
35+
ChromaEnvironment environment = new ChromaEnvironment(Map.of("CHROMA_SERVER_AUTH_CREDENTIALS", "secret"));
36+
assertThat(environment.getKeyToken()).isEqualTo("secret");
37+
}
38+
39+
@Test
40+
void getKeyTokenFromAuthnCredentialsWhenHasCredential() {
3541
ChromaEnvironment environment = new ChromaEnvironment(Map.of("CHROMA_SERVER_AUTHN_CREDENTIALS", "secret"));
3642
assertThat(environment.getKeyToken()).isEqualTo("secret");
3743
}

spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/chroma/ChromaContainerConnectionDetailsFactory.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
2121
import org.testcontainers.chromadb.ChromaDBContainer;
2222

23+
import java.util.Map;
24+
2325
/**
2426
* @author Eddú Meléndez
2527
*/
@@ -37,6 +39,12 @@ public ChromaConnectionDetails getContainerConnectionDetails(ContainerConnection
3739
private static final class ChromaDBContainerConnectionDetails extends ContainerConnectionDetails<ChromaDBContainer>
3840
implements ChromaConnectionDetails {
3941

42+
// Chroma version <= 0.4.x
43+
private static final String CHROMA_SERVER_AUTH_CREDENTIALS = "CHROMA_SERVER_AUTH_CREDENTIALS";
44+
45+
// Chroma version >= 0.5.x
46+
private static final String CHROMA_SERVER_AUTHN_CREDENTIALS = "CHROMA_SERVER_AUTHN_CREDENTIALS";
47+
4048
private ChromaDBContainerConnectionDetails(ContainerConnectionSource<ChromaDBContainer> source) {
4149
super(source);
4250
}
@@ -53,7 +61,11 @@ public int getPort() {
5361

5462
@Override
5563
public String getKeyToken() {
56-
return getContainer().getEnvMap().get("CHROMA_SERVER_AUTHN_CREDENTIALS");
64+
Map<String, String> envVars = getContainer().getEnvMap();
65+
if (envVars.containsKey(CHROMA_SERVER_AUTH_CREDENTIALS)) {
66+
return envVars.get(CHROMA_SERVER_AUTH_CREDENTIALS);
67+
}
68+
return envVars.get(CHROMA_SERVER_AUTHN_CREDENTIALS);
5769
}
5870

5971
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2023 - 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.ai.testcontainers.service.connection.chroma;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.springframework.ai.autoconfigure.vectorstore.chroma.ChromaVectorStoreAutoConfiguration;
20+
import org.springframework.ai.document.Document;
21+
import org.springframework.ai.embedding.EmbeddingModel;
22+
import org.springframework.ai.transformers.TransformersEmbeddingModel;
23+
import org.springframework.ai.vectorstore.SearchRequest;
24+
import org.springframework.ai.vectorstore.VectorStore;
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
27+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
28+
import org.springframework.context.annotation.Bean;
29+
import org.springframework.context.annotation.Configuration;
30+
import org.springframework.test.context.TestPropertySource;
31+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
32+
import org.testcontainers.chromadb.ChromaDBContainer;
33+
import org.testcontainers.junit.jupiter.Container;
34+
import org.testcontainers.junit.jupiter.Testcontainers;
35+
36+
import java.util.List;
37+
import java.util.Map;
38+
39+
import static org.assertj.core.api.Assertions.assertThat;
40+
41+
@SpringJUnitConfig
42+
@Testcontainers
43+
@TestPropertySource(properties = "spring.ai.vectorstore.chroma.store.collectionName=TestCollection")
44+
class ChromaWithToken2ContainerConnectionDetailsFactoryTest {
45+
46+
@Container
47+
@ServiceConnection
48+
static ChromaDBContainer chroma = new ChromaDBContainer("ghcr.io/chroma-core/chroma:0.4.24")
49+
.withEnv("CHROMA_SERVER_AUTH_CREDENTIALS", "token")
50+
.withEnv("CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER",
51+
"chromadb.auth.token.TokenConfigServerAuthCredentialsProvider")
52+
.withEnv("CHROMA_SERVER_AUTH_PROVIDER", "chromadb.auth.token.TokenAuthServerProvider");
53+
54+
@Autowired
55+
private VectorStore vectorStore;
56+
57+
@Test
58+
public void addAndSearchWithFilters() {
59+
var bgDocument = new Document("The World is Big and Salvation Lurks Around the Corner",
60+
Map.of("country", "Bulgaria"));
61+
var nlDocument = new Document("The World is Big and Salvation Lurks Around the Corner",
62+
Map.of("country", "Netherlands"));
63+
64+
vectorStore.add(List.of(bgDocument, nlDocument));
65+
66+
var request = SearchRequest.query("The World").withTopK(5);
67+
68+
List<Document> results = vectorStore.similaritySearch(request);
69+
assertThat(results).hasSize(2);
70+
71+
results = vectorStore
72+
.similaritySearch(request.withSimilarityThresholdAll().withFilterExpression("country == 'Bulgaria'"));
73+
assertThat(results).hasSize(1);
74+
assertThat(results.get(0).getId()).isEqualTo(bgDocument.getId());
75+
76+
results = vectorStore
77+
.similaritySearch(request.withSimilarityThresholdAll().withFilterExpression("country == 'Netherlands'"));
78+
assertThat(results).hasSize(1);
79+
assertThat(results.get(0).getId()).isEqualTo(nlDocument.getId());
80+
81+
// Remove all documents from the store
82+
vectorStore.delete(List.of(bgDocument, nlDocument).stream().map(doc -> doc.getId()).toList());
83+
}
84+
85+
@Configuration(proxyBeanMethods = false)
86+
@ImportAutoConfiguration(ChromaVectorStoreAutoConfiguration.class)
87+
static class Config {
88+
89+
@Bean
90+
public EmbeddingModel embeddingModel() {
91+
return new TransformersEmbeddingModel();
92+
}
93+
94+
}
95+
96+
}

0 commit comments

Comments
 (0)