Skip to content

Commit 6ad8478

Browse files
committed
Use TypesenseContainer for Service Connection
Testcontainers 1.20.4 provides a new module for typesense with TypesenseContainer implementation.
1 parent 5dbfbf9 commit 6ad8478

File tree

9 files changed

+47
-43
lines changed

9 files changed

+47
-43
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
@@ -525,6 +525,13 @@
525525
<scope>test</scope>
526526
</dependency>
527527

528+
<dependency>
529+
<groupId>org.testcontainers</groupId>
530+
<artifactId>typesense</artifactId>
531+
<version>1.20.4</version>
532+
<scope>test</scope>
533+
</dependency>
534+
528535
<dependency>
529536
<groupId>org.testcontainers</groupId>
530537
<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/TypesenseContainerConnectionDetailsFactoryTest.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 TypesenseContainerConnectionDetailsFactoryTest {
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/TypesenseVectorStoreIT.java

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

2828
import org.junit.jupiter.api.Test;
29-
import org.testcontainers.containers.GenericContainer;
3029
import org.testcontainers.junit.jupiter.Container;
3130
import org.testcontainers.junit.jupiter.Testcontainers;
31+
import org.testcontainers.typesense.TypesenseContainer;
3232
import org.typesense.api.Client;
3333
import org.typesense.api.Configuration;
3434
import org.typesense.resources.Node;
@@ -56,9 +56,7 @@
5656
public class TypesenseVectorStoreIT {
5757

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

6361
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
6462
.withUserConfiguration(TestApplication.class);
@@ -250,10 +248,9 @@ public VectorStore vectorStore(Client client, EmbeddingModel embeddingModel) {
250248
@Bean
251249
public Client typesenseClient() {
252250
List<Node> nodes = new ArrayList<>();
253-
nodes
254-
.add(new Node("http", typesenseContainer.getHost(), typesenseContainer.getMappedPort(8108).toString()));
251+
nodes.add(new Node("http", typesense.getHost(), typesense.getMappedPort(8108).toString()));
255252

256-
Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), "xyz");
253+
Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), typesense.getApiKey());
257254
return new Client(configuration);
258255
}
259256

vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/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;
@@ -56,16 +56,15 @@
5656
/**
5757
* @author Christian Tzolov
5858
* @author Thomas Vitale
59+
* @author Eddú Meléndez
5960
*/
6061
@Testcontainers
6162
public class TypesenseVectorStoreObservationIT {
6263

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

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

7069
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
7170
.withUserConfiguration(Config.class);
@@ -181,10 +180,9 @@ public VectorStore vectorStore(Client client, EmbeddingModel embeddingModel,
181180
@Bean
182181
public Client typesenseClient() {
183182
List<Node> nodes = new ArrayList<>();
184-
nodes
185-
.add(new Node("http", typesenseContainer.getHost(), typesenseContainer.getMappedPort(8108).toString()));
183+
nodes.add(new Node("http", typesense.getHost(), typesense.getMappedPort(8108).toString()));
186184

187-
Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), "xyz");
185+
Configuration configuration = new Configuration(nodes, Duration.ofSeconds(5), typesense.getApiKey());
188186
return new Client(configuration);
189187
}
190188

0 commit comments

Comments
 (0)