Skip to content

Commit 163d225

Browse files
committed
Use TypesenseContainer for Service Connection
Testcontainers 1.20.4 provides a new module for typesense with TypesenseContainer implementation.
1 parent eccf33a commit 163d225

File tree

9 files changed

+48
-44
lines changed

9 files changed

+48
-44
lines changed

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/testcontainers.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ The following service connection factories are provided in the `spring-ai-spring
5454
| Containers of type `QdrantContainer`
5555

5656
| `TypesenseConnectionDetails`
57-
| Containers named "typesense/typesense"
57+
| Containers of type `TypesenseContainer`
5858

5959
| `WeaviateConnectionDetails`
6060
| Containers of type `WeaviateContainer`

spring-ai-spring-boot-autoconfigure/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,13 @@
545545
<scope>test</scope>
546546
</dependency>
547547

548+
<dependency>
549+
<groupId>org.testcontainers</groupId>
550+
<artifactId>typesense</artifactId>
551+
<version>1.20.4</version>
552+
<scope>test</scope>
553+
</dependency>
554+
548555
<dependency>
549556
<groupId>org.testcontainers</groupId>
550557
<artifactId>weaviate</artifactId>

spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfigurationIT.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@
1616

1717
package org.springframework.ai.autoconfigure.vectorstore.typesense;
1818

19-
import java.time.Duration;
2019
import java.util.List;
2120
import java.util.Map;
2221

2322
import io.micrometer.observation.tck.TestObservationRegistry;
2423
import org.junit.jupiter.api.Test;
25-
import org.testcontainers.containers.GenericContainer;
2624
import org.testcontainers.junit.jupiter.Container;
2725
import org.testcontainers.junit.jupiter.Testcontainers;
2826

@@ -38,6 +36,7 @@
3836
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3937
import org.springframework.context.annotation.Bean;
4038
import org.springframework.context.annotation.Configuration;
39+
import org.testcontainers.typesense.TypesenseContainer;
4140

4241
import static org.assertj.core.api.Assertions.assertThat;
4342
import static org.springframework.ai.autoconfigure.vectorstore.observation.ObservationTestUtil.assertObservationRegistry;
@@ -53,10 +52,7 @@
5352
public class TypesenseVectorStoreAutoConfigurationIT {
5453

5554
@Container
56-
private static final GenericContainer<?> typesenseContainer = new GenericContainer<>("typesense/typesense:26.0")
57-
.withExposedPorts(8108)
58-
.withCommand("--data-dir", "/tmp", "--api-key=xyz", "--enable-cors")
59-
.withStartupTimeout(Duration.ofSeconds(100));
55+
private static final TypesenseContainer typesense = new TypesenseContainer("typesense/typesense:26.0");
6056

6157
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
6258
.withConfiguration(AutoConfigurations.of(TypesenseVectorStoreAutoConfiguration.class))
@@ -73,10 +69,10 @@ public void addAndSearch() {
7369
.withPropertyValues("spring.ai.vectorstore.typesense.embeddingDimension=384",
7470
"spring.ai.vectorstore.typesense.collectionName=myTestCollection",
7571
"spring.ai.vectorstore.typesense.initialize-schema=true",
76-
"spring.ai.vectorstore.typesense.client.apiKey=xyz",
72+
"spring.ai.vectorstore.typesense.client.apiKey=" + typesense.getApiKey(),
7773
"spring.ai.vectorstore.typesense.client.protocol=http",
78-
"spring.ai.vectorstore.typesense.client.host=" + typesenseContainer.getHost(),
79-
"spring.ai.vectorstore.typesense.client.port=" + typesenseContainer.getMappedPort(8108).toString())
74+
"spring.ai.vectorstore.typesense.client.host=" + typesense.getHost(),
75+
"spring.ai.vectorstore.typesense.client.port=" + typesense.getHttpPort())
8076
.run(context -> {
8177
VectorStore vectorStore = context.getBean(VectorStore.class);
8278
TestObservationRegistry observationRegistry = context.getBean(TestObservationRegistry.class);

spring-ai-spring-boot-testcontainers/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,13 @@
285285
<artifactId>ollama</artifactId>
286286
<optional>true</optional>
287287
</dependency>
288+
289+
<dependency>
290+
<groupId>org.testcontainers</groupId>
291+
<artifactId>typesense</artifactId>
292+
<version>1.20.4</version>
293+
<optional>true</optional>
294+
</dependency>
288295

289296
<dependency>
290297
<groupId>org.opensearch</groupId>

spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactory.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package org.springframework.ai.testcontainers.service.connection.typesense;
1818

19-
import org.testcontainers.containers.Container;
19+
import org.testcontainers.typesense.TypesenseContainer;
2020

2121
import org.springframework.ai.autoconfigure.vectorstore.typesense.TypesenseConnectionDetails;
2222
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
@@ -26,24 +26,21 @@
2626
* @author Eddú Meléndez
2727
*/
2828
class TypesenseContainerConnectionDetailsFactory
29-
extends ContainerConnectionDetailsFactory<Container<?>, TypesenseConnectionDetails> {
30-
31-
TypesenseContainerConnectionDetailsFactory() {
32-
super("typesense/typesense");
33-
}
29+
extends ContainerConnectionDetailsFactory<TypesenseContainer, TypesenseConnectionDetails> {
3430

3531
@Override
36-
protected TypesenseConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
32+
protected TypesenseConnectionDetails getContainerConnectionDetails(
33+
ContainerConnectionSource<TypesenseContainer> source) {
3734
return new TypesenseContainerConnectionDetails(source);
3835
}
3936

4037
/**
4138
* {@link TypesenseConnectionDetails} backed by a {@link ContainerConnectionSource}.
4239
*/
43-
private static final class TypesenseContainerConnectionDetails extends ContainerConnectionDetails<Container<?>>
44-
implements TypesenseConnectionDetails {
40+
private static final class TypesenseContainerConnectionDetails
41+
extends ContainerConnectionDetails<TypesenseContainer> implements TypesenseConnectionDetails {
4542

46-
private TypesenseContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
43+
private TypesenseContainerConnectionDetails(ContainerConnectionSource<TypesenseContainer> source) {
4744
super(source);
4845
}
4946

@@ -59,12 +56,12 @@ public String getProtocol() {
5956

6057
@Override
6158
public int getPort() {
62-
return getContainer().getMappedPort(8108);
59+
return Integer.parseInt(getContainer().getHttpPort());
6360
}
6461

6562
@Override
6663
public String getApiKey() {
67-
return getContainer().getEnvMap().get("TYPESENSE_API_KEY");
64+
return getContainer().getApiKey();
6865
}
6966

7067
}

spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/typesense/TypesenseContainerConnectionDetailsFactoryIT.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@
1616

1717
package org.springframework.ai.testcontainers.service.connection.typesense;
1818

19-
import java.time.Duration;
2019
import java.util.List;
2120
import java.util.Map;
2221

2322
import org.junit.jupiter.api.Test;
24-
import org.testcontainers.containers.GenericContainer;
2523
import org.testcontainers.junit.jupiter.Container;
2624
import org.testcontainers.junit.jupiter.Testcontainers;
2725

@@ -39,6 +37,7 @@
3937
import org.springframework.context.annotation.Configuration;
4038
import org.springframework.test.context.TestPropertySource;
4139
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
40+
import org.testcontainers.typesense.TypesenseContainer;
4241

4342
import static org.assertj.core.api.Assertions.assertThat;
4443

@@ -51,11 +50,7 @@ class TypesenseContainerConnectionDetailsFactoryIT {
5150

5251
@Container
5352
@ServiceConnection
54-
private static final GenericContainer<?> typesense = new GenericContainer<>(TypesenseImage.DEFAULT_IMAGE)
55-
.withExposedPorts(8108)
56-
.withCommand("--data-dir", "/tmp", "--enable-cors")
57-
.withEnv("TYPESENSE_API_KEY", "secret")
58-
.withStartupTimeout(Duration.ofSeconds(100));
53+
private static final TypesenseContainer typesense = new TypesenseContainer(TypesenseImage.DEFAULT_IMAGE);
5954

6055
List<Document> documents = List.of(
6156
new Document(ResourceUtils.getText("classpath:/test/data/spring.ai.txt"), Map.of("spring", "great")),

vector-stores/spring-ai-typesense-store/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@
8282
<scope>test</scope>
8383
</dependency>
8484

85+
<dependency>
86+
<groupId>org.testcontainers</groupId>
87+
<artifactId>typesense</artifactId>
88+
<version>1.20.4</version>
89+
<scope>test</scope>
90+
</dependency>
91+
8592

8693
<dependency>
8794
<groupId>io.micrometer</groupId>

vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@
2626
import java.util.UUID;
2727

2828
import org.junit.jupiter.api.Test;
29-
import org.springframework.ai.document.DocumentMetadata;
30-
import org.testcontainers.containers.GenericContainer;
3129
import org.testcontainers.junit.jupiter.Container;
3230
import org.testcontainers.junit.jupiter.Testcontainers;
31+
import org.testcontainers.typesense.TypesenseContainer;
3332
import org.typesense.api.Client;
3433
import org.typesense.api.Configuration;
3534
import org.typesense.resources.Node;
3635

3736
import org.springframework.ai.document.Document;
37+
import org.springframework.ai.document.DocumentMetadata;
3838
import org.springframework.ai.embedding.EmbeddingModel;
3939
import org.springframework.ai.transformers.TransformersEmbeddingModel;
4040
import org.springframework.ai.vectorstore.SearchRequest;
@@ -58,9 +58,7 @@
5858
public class TypesenseVectorStoreIT {
5959

6060
@Container
61-
private static GenericContainer<?> typesenseContainer = new GenericContainer<>(TypesenseImage.DEFAULT_IMAGE)
62-
.withExposedPorts(8108)
63-
.withCommand("--data-dir", "/tmp", "--api-key=xyz", "--enable-cors");
61+
private static TypesenseContainer typesense = new TypesenseContainer(TypesenseImage.DEFAULT_IMAGE);
6462

6563
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
6664
.withUserConfiguration(TestApplication.class);
@@ -254,10 +252,9 @@ public VectorStore vectorStore(Client client, EmbeddingModel embeddingModel) {
254252
@Bean
255253
public Client typesenseClient() {
256254
List<Node> nodes = new ArrayList<>();
257-
nodes
258-
.add(new Node("http", typesenseContainer.getHost(), typesenseContainer.getMappedPort(8108).toString()));
255+
nodes.add(new Node("http", typesense.getHost(), typesense.getMappedPort(8108).toString()));
259256

260-
Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), "xyz");
257+
Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), typesense.getApiKey());
261258
return new Client(configuration);
262259
}
263260

vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
import io.micrometer.observation.tck.TestObservationRegistry;
2828
import io.micrometer.observation.tck.TestObservationRegistryAssert;
2929
import org.junit.jupiter.api.Test;
30-
import org.testcontainers.containers.GenericContainer;
3130
import org.testcontainers.junit.jupiter.Container;
3231
import org.testcontainers.junit.jupiter.Testcontainers;
32+
import org.testcontainers.typesense.TypesenseContainer;
3333
import org.typesense.api.Client;
3434
import org.typesense.api.Configuration;
3535
import org.typesense.resources.Node;
@@ -57,16 +57,15 @@
5757
/**
5858
* @author Christian Tzolov
5959
* @author Thomas Vitale
60+
* @author Eddú Meléndez
6061
*/
6162
@Testcontainers
6263
public class TypesenseVectorStoreObservationIT {
6364

6465
private static final String TEST_COLLECTION_NAME = "test_vector_store";
6566

6667
@Container
67-
private static GenericContainer<?> typesenseContainer = new GenericContainer<>(TypesenseImage.DEFAULT_IMAGE)
68-
.withExposedPorts(8108)
69-
.withCommand("--data-dir", "/tmp", "--api-key=xyz", "--enable-cors");
68+
private static TypesenseContainer typesense = new TypesenseContainer(TypesenseImage.DEFAULT_IMAGE);
7069

7170
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
7271
.withUserConfiguration(Config.class);
@@ -185,10 +184,9 @@ public VectorStore vectorStore(Client client, EmbeddingModel embeddingModel,
185184
@Bean
186185
public Client typesenseClient() {
187186
List<Node> nodes = new ArrayList<>();
188-
nodes
189-
.add(new Node("http", typesenseContainer.getHost(), typesenseContainer.getMappedPort(8108).toString()));
187+
nodes.add(new Node("http", typesense.getHost(), typesense.getMappedPort(8108).toString()));
190188

191-
Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), "xyz");
189+
Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), typesense.getApiKey());
192190
return new Client(configuration);
193191
}
194192

0 commit comments

Comments
 (0)