diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/testcontainers.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/testcontainers.adoc
index 44766dc571a..2f8b59d4182 100644
--- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/testcontainers.adoc
+++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/testcontainers.adoc
@@ -54,7 +54,7 @@ The following service connection factories are provided in the `spring-ai-spring
| Containers of type `QdrantContainer`
| `TypesenseConnectionDetails`
-| Containers named "typesense/typesense"
+| Containers of type `TypesenseContainer`
| `WeaviateConnectionDetails`
| Containers of type `WeaviateContainer`
diff --git a/spring-ai-spring-boot-autoconfigure/pom.xml b/spring-ai-spring-boot-autoconfigure/pom.xml
index 92ac01362c6..1ed0b73b640 100644
--- a/spring-ai-spring-boot-autoconfigure/pom.xml
+++ b/spring-ai-spring-boot-autoconfigure/pom.xml
@@ -545,6 +545,13 @@
test
+
+ org.testcontainers
+ typesense
+ 1.20.4
+ test
+
+
org.testcontainers
weaviate
diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfigurationIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfigurationIT.java
index 0911534efc7..2c297ee7748 100644
--- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfigurationIT.java
+++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfigurationIT.java
@@ -16,15 +16,14 @@
package org.springframework.ai.autoconfigure.vectorstore.typesense;
-import java.time.Duration;
import java.util.List;
import java.util.Map;
import io.micrometer.observation.tck.TestObservationRegistry;
import org.junit.jupiter.api.Test;
-import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.typesense.TypesenseContainer;
import org.springframework.ai.ResourceUtils;
import org.springframework.ai.document.Document;
@@ -53,10 +52,7 @@
public class TypesenseVectorStoreAutoConfigurationIT {
@Container
- private static final GenericContainer> typesenseContainer = new GenericContainer<>("typesense/typesense:26.0")
- .withExposedPorts(8108)
- .withCommand("--data-dir", "/tmp", "--api-key=xyz", "--enable-cors")
- .withStartupTimeout(Duration.ofSeconds(100));
+ private static final TypesenseContainer typesense = new TypesenseContainer("typesense/typesense:26.0");
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(TypesenseVectorStoreAutoConfiguration.class))
@@ -73,10 +69,10 @@ public void addAndSearch() {
.withPropertyValues("spring.ai.vectorstore.typesense.embeddingDimension=384",
"spring.ai.vectorstore.typesense.collectionName=myTestCollection",
"spring.ai.vectorstore.typesense.initialize-schema=true",
- "spring.ai.vectorstore.typesense.client.apiKey=xyz",
+ "spring.ai.vectorstore.typesense.client.apiKey=" + typesense.getApiKey(),
"spring.ai.vectorstore.typesense.client.protocol=http",
- "spring.ai.vectorstore.typesense.client.host=" + typesenseContainer.getHost(),
- "spring.ai.vectorstore.typesense.client.port=" + typesenseContainer.getMappedPort(8108).toString())
+ "spring.ai.vectorstore.typesense.client.host=" + typesense.getHost(),
+ "spring.ai.vectorstore.typesense.client.port=" + typesense.getHttpPort())
.run(context -> {
VectorStore vectorStore = context.getBean(VectorStore.class);
TestObservationRegistry observationRegistry = context.getBean(TestObservationRegistry.class);
diff --git a/spring-ai-spring-boot-testcontainers/pom.xml b/spring-ai-spring-boot-testcontainers/pom.xml
index ed7bef8c268..72db035a181 100644
--- a/spring-ai-spring-boot-testcontainers/pom.xml
+++ b/spring-ai-spring-boot-testcontainers/pom.xml
@@ -285,6 +285,13 @@
ollama
true
+
+
+ org.testcontainers
+ typesense
+ 1.20.4
+ true
+
org.opensearch
diff --git a/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactory.java b/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactory.java
index 68769925a9d..f2bc175c026 100644
--- a/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactory.java
+++ b/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactory.java
@@ -16,7 +16,7 @@
package org.springframework.ai.testcontainers.service.connection.typesense;
-import org.testcontainers.containers.Container;
+import org.testcontainers.typesense.TypesenseContainer;
import org.springframework.ai.autoconfigure.vectorstore.typesense.TypesenseConnectionDetails;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
@@ -26,24 +26,21 @@
* @author Eddú Meléndez
*/
class TypesenseContainerConnectionDetailsFactory
- extends ContainerConnectionDetailsFactory, TypesenseConnectionDetails> {
-
- TypesenseContainerConnectionDetailsFactory() {
- super("typesense/typesense");
- }
+ extends ContainerConnectionDetailsFactory {
@Override
- protected TypesenseConnectionDetails getContainerConnectionDetails(ContainerConnectionSource> source) {
+ protected TypesenseConnectionDetails getContainerConnectionDetails(
+ ContainerConnectionSource source) {
return new TypesenseContainerConnectionDetails(source);
}
/**
* {@link TypesenseConnectionDetails} backed by a {@link ContainerConnectionSource}.
*/
- private static final class TypesenseContainerConnectionDetails extends ContainerConnectionDetails>
- implements TypesenseConnectionDetails {
+ private static final class TypesenseContainerConnectionDetails
+ extends ContainerConnectionDetails implements TypesenseConnectionDetails {
- private TypesenseContainerConnectionDetails(ContainerConnectionSource> source) {
+ private TypesenseContainerConnectionDetails(ContainerConnectionSource source) {
super(source);
}
@@ -59,12 +56,12 @@ public String getProtocol() {
@Override
public int getPort() {
- return getContainer().getMappedPort(8108);
+ return Integer.parseInt(getContainer().getHttpPort());
}
@Override
public String getApiKey() {
- return getContainer().getEnvMap().get("TYPESENSE_API_KEY");
+ return getContainer().getApiKey();
}
}
diff --git a/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactoryIT.java b/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactoryIT.java
index 9ba47d474b2..b6b8c3b3f1a 100644
--- a/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactoryIT.java
+++ b/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactoryIT.java
@@ -16,14 +16,13 @@
package org.springframework.ai.testcontainers.service.connection.typesense;
-import java.time.Duration;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
-import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.typesense.TypesenseContainer;
import org.springframework.ai.ResourceUtils;
import org.springframework.ai.autoconfigure.vectorstore.typesense.TypesenseVectorStoreAutoConfiguration;
@@ -51,11 +50,7 @@ class TypesenseContainerConnectionDetailsFactoryIT {
@Container
@ServiceConnection
- private static final GenericContainer> typesense = new GenericContainer<>(TypesenseImage.DEFAULT_IMAGE)
- .withExposedPorts(8108)
- .withCommand("--data-dir", "/tmp", "--enable-cors")
- .withEnv("TYPESENSE_API_KEY", "secret")
- .withStartupTimeout(Duration.ofSeconds(100));
+ private static final TypesenseContainer typesense = new TypesenseContainer(TypesenseImage.DEFAULT_IMAGE);
List documents = List.of(
new Document(ResourceUtils.getText("classpath:/test/data/spring.ai.txt"), Map.of("spring", "great")),
diff --git a/vector-stores/spring-ai-typesense-store/pom.xml b/vector-stores/spring-ai-typesense-store/pom.xml
index 83d13e75f2d..dc4e20e8d97 100644
--- a/vector-stores/spring-ai-typesense-store/pom.xml
+++ b/vector-stores/spring-ai-typesense-store/pom.xml
@@ -82,6 +82,13 @@
test
+
+ org.testcontainers
+ typesense
+ 1.20.4
+ test
+
+
io.micrometer
diff --git a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java
index bfa8374ee0b..f275d4b2f9f 100644
--- a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java
+++ b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java
@@ -26,9 +26,10 @@
import java.util.UUID;
import org.junit.jupiter.api.Test;
-import org.testcontainers.containers.GenericContainer;
+
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.typesense.TypesenseContainer;
import org.typesense.api.Client;
import org.typesense.api.Configuration;
import org.typesense.resources.Node;
@@ -58,9 +59,7 @@
public class TypesenseVectorStoreIT {
@Container
- private static GenericContainer> typesenseContainer = new GenericContainer<>(TypesenseImage.DEFAULT_IMAGE)
- .withExposedPorts(8108)
- .withCommand("--data-dir", "/tmp", "--api-key=xyz", "--enable-cors");
+ private static TypesenseContainer typesense = new TypesenseContainer(TypesenseImage.DEFAULT_IMAGE);
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(TestApplication.class);
@@ -262,10 +261,9 @@ public VectorStore vectorStore(Client client, EmbeddingModel embeddingModel) {
@Bean
public Client typesenseClient() {
List nodes = new ArrayList<>();
- nodes
- .add(new Node("http", typesenseContainer.getHost(), typesenseContainer.getMappedPort(8108).toString()));
+ nodes.add(new Node("http", typesense.getHost(), typesense.getMappedPort(8108).toString()));
- Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), "xyz");
+ Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), typesense.getApiKey());
return new Client(configuration);
}
diff --git a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java
index 308291c05a5..7b8b97b0f16 100644
--- a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java
+++ b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java
@@ -27,9 +27,9 @@
import io.micrometer.observation.tck.TestObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistryAssert;
import org.junit.jupiter.api.Test;
-import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.typesense.TypesenseContainer;
import org.typesense.api.Client;
import org.typesense.api.Configuration;
import org.typesense.resources.Node;
@@ -57,6 +57,7 @@
/**
* @author Christian Tzolov
* @author Thomas Vitale
+ * @author Eddú Meléndez
*/
@Testcontainers
public class TypesenseVectorStoreObservationIT {
@@ -64,9 +65,7 @@ public class TypesenseVectorStoreObservationIT {
private static final String TEST_COLLECTION_NAME = "test_vector_store";
@Container
- private static GenericContainer> typesenseContainer = new GenericContainer<>(TypesenseImage.DEFAULT_IMAGE)
- .withExposedPorts(8108)
- .withCommand("--data-dir", "/tmp", "--api-key=xyz", "--enable-cors");
+ private static TypesenseContainer typesense = new TypesenseContainer(TypesenseImage.DEFAULT_IMAGE);
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(Config.class);
@@ -183,10 +182,9 @@ public VectorStore vectorStore(Client client, EmbeddingModel embeddingModel,
@Bean
public Client typesenseClient() {
List nodes = new ArrayList<>();
- nodes
- .add(new Node("http", typesenseContainer.getHost(), typesenseContainer.getMappedPort(8108).toString()));
+ nodes.add(new Node("http", typesense.getHost(), typesense.getMappedPort(8108).toString()));
- Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), "xyz");
+ Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), typesense.getApiKey());
return new Client(configuration);
}