Use TypesenseContainer for Service Connection

Testcontainers 1.20.4 provides a new module for typesense with
TypesenseContainer implementation.

Signed-off-by: Eddú Meléndez <eddu.melendez@gmail.com>
This commit is contained in:
Eddú Meléndez
2024-11-20 11:46:07 -06:00
committed by Mark Pollack
parent 2f14597ccb
commit 840304955e
9 changed files with 48 additions and 43 deletions

View File

@@ -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`

View File

@@ -545,6 +545,13 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>typesense</artifactId>
<version>1.20.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>weaviate</artifactId>

View File

@@ -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 @@ import static org.springframework.ai.autoconfigure.vectorstore.observation.Obser
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 class TypesenseVectorStoreAutoConfigurationIT {
.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);

View File

@@ -285,6 +285,13 @@
<artifactId>ollama</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>typesense</artifactId>
<version>1.20.4</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.opensearch</groupId>

View File

@@ -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 @@ import org.springframework.boot.testcontainers.service.connection.ContainerConne
* @author Eddú Meléndez
*/
class TypesenseContainerConnectionDetailsFactory
extends ContainerConnectionDetailsFactory<Container<?>, TypesenseConnectionDetails> {
TypesenseContainerConnectionDetailsFactory() {
super("typesense/typesense");
}
extends ContainerConnectionDetailsFactory<TypesenseContainer, TypesenseConnectionDetails> {
@Override
protected TypesenseConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
protected TypesenseConnectionDetails getContainerConnectionDetails(
ContainerConnectionSource<TypesenseContainer> source) {
return new TypesenseContainerConnectionDetails(source);
}
/**
* {@link TypesenseConnectionDetails} backed by a {@link ContainerConnectionSource}.
*/
private static final class TypesenseContainerConnectionDetails extends ContainerConnectionDetails<Container<?>>
implements TypesenseConnectionDetails {
private static final class TypesenseContainerConnectionDetails
extends ContainerConnectionDetails<TypesenseContainer> implements TypesenseConnectionDetails {
private TypesenseContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
private TypesenseContainerConnectionDetails(ContainerConnectionSource<TypesenseContainer> source) {
super(source);
}
@@ -59,12 +56,12 @@ class TypesenseContainerConnectionDetailsFactory
@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();
}
}

View File

@@ -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<Document> documents = List.of(
new Document(ResourceUtils.getText("classpath:/test/data/spring.ai.txt"), Map.of("spring", "great")),

View File

@@ -82,6 +82,13 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>typesense</artifactId>
<version>1.20.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>

View File

@@ -26,9 +26,10 @@ import java.util.Map;
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 @@ import static org.assertj.core.api.Assertions.assertThat;
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 class TypesenseVectorStoreIT {
@Bean
public Client typesenseClient() {
List<Node> 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);
}

View File

@@ -27,9 +27,9 @@ import io.micrometer.observation.ObservationRegistry;
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 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @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 class TypesenseVectorStoreObservationIT {
@Bean
public Client typesenseClient() {
List<Node> 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);
}