Skip to content

Commit 2c5aca7

Browse files
committed
test: Add comprehensive test coverage for QdrantObjectFactory and QdrantVectorStore.Builder
Signed-off-by: Alex Klimenko <[email protected]>
1 parent e0ccc13 commit 2c5aca7

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantObjectFactoryTests.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.junit.jupiter.api.Test;
2424

2525
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2627

2728
/**
2829
* Tests for {@link QdrantObjectFactory}.
@@ -50,4 +51,66 @@ void toObjectMapShouldHandleNullValues() {
5051
assertThat(result.get("description")).isNull();
5152
}
5253

54+
@Test
55+
void toObjectMapShouldHandleEmptyMap() {
56+
Map<String, Value> emptyPayload = Map.of();
57+
58+
Map<String, Object> result = QdrantObjectFactory.toObjectMap(emptyPayload);
59+
60+
assertThat(result).isNotNull();
61+
assertThat(result).isEmpty();
62+
}
63+
64+
@Test
65+
void toObjectMapShouldHandleAllPrimitiveTypes() {
66+
Map<String, Value> payload = Map.of("stringField", Value.newBuilder().setStringValue("test").build(),
67+
"intField", Value.newBuilder().setIntegerValue(1).build(), "doubleField",
68+
Value.newBuilder().setDoubleValue(1.1).build(), "boolField",
69+
Value.newBuilder().setBoolValue(false).build());
70+
71+
Map<String, Object> result = QdrantObjectFactory.toObjectMap(payload);
72+
73+
assertThat(result).hasSize(4);
74+
assertThat(result.get("stringField")).isEqualTo("test");
75+
assertThat(result.get("intField")).isEqualTo(1L);
76+
assertThat(result.get("doubleField")).isEqualTo(1.1);
77+
assertThat(result.get("boolField")).isEqualTo(false);
78+
}
79+
80+
@Test
81+
void toObjectMapShouldHandleKindNotSetValue() {
82+
// This test verifies that KIND_NOT_SET values are handled gracefully
83+
Value kindNotSetValue = Value.newBuilder().build(); // Default case - KIND_NOT_SET
84+
85+
Map<String, Value> payload = Map.of("unsetField", kindNotSetValue);
86+
87+
Map<String, Object> result = QdrantObjectFactory.toObjectMap(payload);
88+
89+
assertThat(result).hasSize(1);
90+
assertThat(result.get("unsetField")).isNull();
91+
}
92+
93+
@Test
94+
void toObjectMapShouldThrowExceptionForNullPayload() {
95+
assertThatThrownBy(() -> QdrantObjectFactory.toObjectMap(null)).isInstanceOf(IllegalArgumentException.class)
96+
.hasMessage("Payload map must not be null");
97+
}
98+
99+
@Test
100+
void toObjectMapShouldHandleMixedDataTypes() {
101+
Map<String, Value> payload = Map.of("text", Value.newBuilder().setStringValue("").build(), // empty
102+
// string
103+
"flag", Value.newBuilder().setBoolValue(true).build(), "nullField",
104+
Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(), "number",
105+
Value.newBuilder().setIntegerValue(1).build());
106+
107+
Map<String, Object> result = QdrantObjectFactory.toObjectMap(payload);
108+
109+
assertThat(result).hasSize(4);
110+
assertThat(result.get("text")).isEqualTo("");
111+
assertThat(result.get("flag")).isEqualTo(true);
112+
assertThat(result.get("nullField")).isNull();
113+
assertThat(result.get("number")).isEqualTo(1L);
114+
}
115+
53116
}

vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreBuilderTests.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,4 +235,100 @@ void builderShouldHandleBooleanToggling() {
235235
assertThat(vectorStore3).hasFieldOrPropertyWithValue("initializeSchema", true);
236236
}
237237

238+
@Test
239+
void builderShouldPreserveMockedDependencies() {
240+
QdrantVectorStore vectorStore = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel).build();
241+
242+
assertThat(vectorStore).hasFieldOrPropertyWithValue("qdrantClient", this.qdrantClient);
243+
assertThat(vectorStore).hasFieldOrPropertyWithValue("embeddingModel", this.embeddingModel);
244+
}
245+
246+
@Test
247+
void builderShouldCreateImmutableConfiguration() {
248+
QdrantVectorStore.Builder builder = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
249+
.collectionName("test_collection")
250+
.initializeSchema(true);
251+
252+
QdrantVectorStore vectorStore1 = builder.build();
253+
254+
// Modify builder after first build
255+
builder.collectionName("different_collection").initializeSchema(false);
256+
QdrantVectorStore vectorStore2 = builder.build();
257+
258+
// First vector store should remain unchanged
259+
assertThat(vectorStore1).hasFieldOrPropertyWithValue("collectionName", "test_collection");
260+
assertThat(vectorStore1).hasFieldOrPropertyWithValue("initializeSchema", true);
261+
262+
// Second vector store should have new values
263+
assertThat(vectorStore2).hasFieldOrPropertyWithValue("collectionName", "different_collection");
264+
assertThat(vectorStore2).hasFieldOrPropertyWithValue("initializeSchema", false);
265+
}
266+
267+
@Test
268+
void builderShouldHandleNullQdrantClientCorrectly() {
269+
assertThatThrownBy(() -> QdrantVectorStore.builder(null, this.embeddingModel))
270+
.isInstanceOf(IllegalArgumentException.class)
271+
.hasMessage("QdrantClient must not be null");
272+
}
273+
274+
@Test
275+
void builderShouldValidateConfigurationOnBuild() {
276+
QdrantVectorStore.Builder builder = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel);
277+
278+
// Should succeed with valid configuration
279+
assertThat(builder.build()).isNotNull();
280+
281+
// Should fail when trying to build with invalid configuration set later
282+
assertThatThrownBy(() -> builder.collectionName("").build()).isInstanceOf(IllegalArgumentException.class)
283+
.hasMessage("collectionName must not be empty");
284+
}
285+
286+
@Test
287+
void builderShouldRetainLastSetBatchingStrategy() {
288+
TokenCountBatchingStrategy strategy1 = new TokenCountBatchingStrategy();
289+
TokenCountBatchingStrategy strategy2 = new TokenCountBatchingStrategy();
290+
TokenCountBatchingStrategy strategy3 = new TokenCountBatchingStrategy();
291+
292+
QdrantVectorStore vectorStore = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
293+
.batchingStrategy(strategy1)
294+
.batchingStrategy(strategy2)
295+
.batchingStrategy(strategy3)
296+
.build();
297+
298+
assertThat(vectorStore).hasFieldOrPropertyWithValue("batchingStrategy", strategy3);
299+
}
300+
301+
@Test
302+
void builderShouldHandleCollectionNameEdgeCases() {
303+
// Test single character collection name
304+
QdrantVectorStore vectorStore1 = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
305+
.collectionName("a")
306+
.build();
307+
assertThat(vectorStore1).hasFieldOrPropertyWithValue("collectionName", "a");
308+
309+
// Test collection name with numbers only
310+
QdrantVectorStore vectorStore2 = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
311+
.collectionName("12345")
312+
.build();
313+
assertThat(vectorStore2).hasFieldOrPropertyWithValue("collectionName", "12345");
314+
315+
// Test collection name starting with number
316+
QdrantVectorStore vectorStore3 = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
317+
.collectionName("1collection")
318+
.build();
319+
assertThat(vectorStore3).hasFieldOrPropertyWithValue("collectionName", "1collection");
320+
}
321+
322+
@Test
323+
void builderShouldMaintainBuilderPattern() {
324+
QdrantVectorStore.Builder builder = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel);
325+
326+
// Each method should return the builder for chaining
327+
QdrantVectorStore.Builder result = builder.collectionName("test")
328+
.initializeSchema(true)
329+
.batchingStrategy(new TokenCountBatchingStrategy());
330+
331+
assertThat(result).isSameAs(builder);
332+
}
333+
238334
}

0 commit comments

Comments
 (0)