Initial commit
This commit is contained in:
@@ -0,0 +1,330 @@
|
||||
# Integration Testing with Testcontainers
|
||||
|
||||
## Ollama Integration Test Setup
|
||||
|
||||
```java
|
||||
import dev.langchain4j.model.chat.ChatModel;
|
||||
import dev.langchain4j.model.ollama.OllamaChatModel;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
@Testcontainers
|
||||
class OllamaIntegrationTest {
|
||||
|
||||
@Container
|
||||
static GenericContainer<?> ollama = new GenericContainer<>(
|
||||
DockerImageName.parse("ollama/ollama:latest")
|
||||
).withExposedPorts(11434);
|
||||
|
||||
private static ChatModel chatModel;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
chatModel = OllamaChatModel.builder()
|
||||
.baseUrl(ollama.getEndpoint())
|
||||
.modelName("llama2") // Use a lightweight model for testing
|
||||
.temperature(0.0)
|
||||
.timeout(java.time.Duration.ofSeconds(30))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGenerateResponseWithOllama() {
|
||||
// Act
|
||||
String response = chatModel.generate("What is 2 + 2?");
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertFalse(response.trim().isEmpty());
|
||||
assertTrue(response.contains("4") || response.toLowerCase().contains("four"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleComplexQuery() {
|
||||
// Act
|
||||
String response = chatModel.generate(
|
||||
"Explain the difference between ArrayList and LinkedList in Java"
|
||||
);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertTrue(response.length() > 50);
|
||||
assertTrue(response.toLowerCase().contains("arraylist"));
|
||||
assertTrue(response.toLowerCase().contains("linkedlist"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Embedding Store Integration Test
|
||||
|
||||
```java
|
||||
import dev.langchain4j.data.embedding.Embedding;
|
||||
import dev.langchain4j.data.segment.TextSegment;
|
||||
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||
import dev.langchain4j.model.ollama.OllamaEmbeddingModel;
|
||||
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class EmbeddingStoreIntegrationTest {
|
||||
|
||||
private EmbeddingModel embeddingModel;
|
||||
private EmbeddingStore<TextSegment> embeddingStore;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
// Use in-memory store for faster tests
|
||||
embeddingStore = new InMemoryEmbeddingStore();
|
||||
|
||||
// For production tests, you could use Testcontainers with Chroma/Weaviate
|
||||
embeddingModel = OllamaEmbeddingModel.builder()
|
||||
.baseUrl("http://localhost:11434")
|
||||
.modelName("nomic-embed-text")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldStoreAndRetrieveEmbeddings() {
|
||||
// Arrange
|
||||
TextSegment segment = TextSegment.from("Java is a programming language");
|
||||
Embedding embedding = embeddingModel.embed(segment.text()).content();
|
||||
|
||||
// Act
|
||||
String id = embeddingStore.add(embedding, segment);
|
||||
|
||||
// Assert
|
||||
assertNotNull(id);
|
||||
|
||||
// Verify retrieval
|
||||
var searchRequest = EmbeddingSearchRequest.builder()
|
||||
.queryEmbedding(embedding)
|
||||
.maxResults(1)
|
||||
.build();
|
||||
|
||||
List<EmbeddingMatch<TextSegment>> matches = embeddingStore.search(searchRequest);
|
||||
assertEquals(1, matches.size());
|
||||
assertEquals(segment.text(), matches.get(0).embedded().text());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## RAG Integration Test
|
||||
|
||||
```java
|
||||
import dev.langchain4j.data.document.Document;
|
||||
import dev.langchain4j.data.document.DocumentSplitter;
|
||||
import dev.langchain4j.data.document.splitter.ParagraphSplitter;
|
||||
import dev.langchain4j.rag.content.retriever.ContentRetriever;
|
||||
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
|
||||
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class RagSystemTest {
|
||||
|
||||
private ContentRetriever contentRetriever;
|
||||
private ChatModel chatModel;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
// Setup embedding store
|
||||
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore();
|
||||
|
||||
// Setup embedding model
|
||||
EmbeddingModel embeddingModel = OllamaEmbeddingModel.builder()
|
||||
.baseUrl("http://localhost:11434")
|
||||
.modelName("nomic-embed-text")
|
||||
.build();
|
||||
|
||||
// Setup content retriever
|
||||
contentRetriever = EmbeddingStoreContentRetriever.builder()
|
||||
.embeddingModel(embeddingModel)
|
||||
.embeddingStore(embeddingStore)
|
||||
.maxResults(3)
|
||||
.build();
|
||||
|
||||
// Setup chat model
|
||||
chatModel = OllamaChatModel.builder()
|
||||
.baseUrl("http://localhost:11434")
|
||||
.modelName("llama2")
|
||||
.build();
|
||||
|
||||
// Ingest test documents
|
||||
ingestTestDocuments(embeddingStore, embeddingModel);
|
||||
}
|
||||
|
||||
private void ingestTestDocuments(EmbeddingStore<TextSegment> store, EmbeddingModel model) {
|
||||
DocumentSplitter splitter = new ParagraphSplitter();
|
||||
|
||||
Document doc1 = Document.from("Spring Boot is a Java framework for building microservices");
|
||||
Document doc2 = Document.from("Maven is a build automation tool for Java projects");
|
||||
Document doc3 = Document.from("JUnit is a testing framework for Java applications");
|
||||
|
||||
List<Document> documents = List.of(doc1, doc2, doc3);
|
||||
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
|
||||
.embeddingModel(model)
|
||||
.embeddingStore(store)
|
||||
.documentSplitter(splitter)
|
||||
.build();
|
||||
|
||||
ingestor.ingest(documents);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRetrieveRelevantContent() {
|
||||
// Arrange
|
||||
RagAssistant assistant = AiServices.builder(RagAssistant.class)
|
||||
.chatLanguageModel(chatModel)
|
||||
.contentRetriever(contentRetriever)
|
||||
.build();
|
||||
|
||||
// Act
|
||||
String response = assistant.chat("What is Spring Boot?");
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertTrue(response.toLowerCase().contains("spring boot"));
|
||||
assertTrue(response.toLowerCase().contains("framework"));
|
||||
}
|
||||
|
||||
interface RagAssistant {
|
||||
String chat(String message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Testing
|
||||
|
||||
### Response Time Test
|
||||
|
||||
```java
|
||||
import dev.langchain4j.model.chat.ChatModel;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PerformanceTest {
|
||||
|
||||
@Test
|
||||
@Timeout(30)
|
||||
void shouldRespondWithinTimeLimit() {
|
||||
// Arrange
|
||||
ChatModel model = OllamaChatModel.builder()
|
||||
.baseUrl("http://localhost:11434")
|
||||
.modelName("llama2")
|
||||
.timeout(Duration.ofSeconds(20))
|
||||
.build();
|
||||
|
||||
// Act
|
||||
Instant start = Instant.now();
|
||||
String response = model.generate("What is 2 + 2?");
|
||||
Instant end = Instant.now();
|
||||
|
||||
// Assert
|
||||
Duration duration = Duration.between(start, end);
|
||||
assertTrue(duration.toSeconds() < 15, "Response took too long: " + duration);
|
||||
assertNotNull(response);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Token Usage Tracking Test
|
||||
|
||||
```java
|
||||
import dev.langchain4j.model.chat.ChatModel;
|
||||
import dev.langchain4j.model.output.TokenUsage;
|
||||
|
||||
@Test
|
||||
void shouldTrackTokenUsage() {
|
||||
// Arrange
|
||||
ChatModel mockModel = mock(ChatModel.class);
|
||||
var mockResponse = Response.from(
|
||||
AiMessage.from("Response"),
|
||||
new TokenUsage(10, 20, 30)
|
||||
);
|
||||
|
||||
when(mockModel.generate(any(String.class)))
|
||||
.thenReturn(mockResponse);
|
||||
|
||||
// Act
|
||||
var response = mockModel.generate("Test query");
|
||||
|
||||
// Assert
|
||||
assertEquals(10, response.tokenUsage().inputTokenCount());
|
||||
assertEquals(20, response.tokenUsage().outputTokenCount());
|
||||
assertEquals(30, response.tokenUsage().totalTokenCount());
|
||||
}
|
||||
```
|
||||
|
||||
## Vector Store Integration Tests
|
||||
|
||||
### Qdrant Integration Test
|
||||
|
||||
```java
|
||||
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||
import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
@Testcontainers
|
||||
class QdrantIntegrationTest {
|
||||
|
||||
@Container
|
||||
static GenericContainer<?> qdrant = new GenericContainer<>(
|
||||
DockerImageName.parse("qdrant/qdrant:latest")
|
||||
).withExposedPorts(6333);
|
||||
|
||||
private EmbeddingStore<TextSegment> embeddingStore;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
var host = qdrant.getHost();
|
||||
var port = qdrant.getFirstMappedPort();
|
||||
|
||||
embeddingStore = QdrantEmbeddingStore.builder()
|
||||
.host(host)
|
||||
.port(port)
|
||||
.collectionName("test-collection")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldStoreAndRetrieveVectors() {
|
||||
// Arrange
|
||||
var text = "Spring Boot is a Java framework";
|
||||
var embeddingModel = createMockEmbeddingModel(text);
|
||||
var segment = TextSegment.from(text);
|
||||
|
||||
// Act
|
||||
String id = embeddingStore.add(embeddingModel.embed(text).content(), segment);
|
||||
|
||||
// Assert
|
||||
assertNotNull(id);
|
||||
|
||||
var searchRequest = EmbeddingSearchRequest.builder()
|
||||
.queryEmbedding(embeddingModel.embed(text).content())
|
||||
.maxResults(1)
|
||||
.build();
|
||||
|
||||
var result = embeddingStore.search(searchRequest);
|
||||
assertEquals(1, result.matches().size());
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user