Skip to content

test: Add comprehensive test coverage for QdrantObjectFactory and QdrantVectorStore.Builder #4051

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
* Tests for {@link QdrantObjectFactory}.
Expand Down Expand Up @@ -50,4 +51,66 @@ void toObjectMapShouldHandleNullValues() {
assertThat(result.get("description")).isNull();
}

@Test
void toObjectMapShouldHandleEmptyMap() {
Map<String, Value> emptyPayload = Map.of();

Map<String, Object> result = QdrantObjectFactory.toObjectMap(emptyPayload);

assertThat(result).isNotNull();
assertThat(result).isEmpty();
}

@Test
void toObjectMapShouldHandleAllPrimitiveTypes() {
Map<String, Value> payload = Map.of("stringField", Value.newBuilder().setStringValue("test").build(),
"intField", Value.newBuilder().setIntegerValue(1).build(), "doubleField",
Value.newBuilder().setDoubleValue(1.1).build(), "boolField",
Value.newBuilder().setBoolValue(false).build());

Map<String, Object> result = QdrantObjectFactory.toObjectMap(payload);

assertThat(result).hasSize(4);
assertThat(result.get("stringField")).isEqualTo("test");
assertThat(result.get("intField")).isEqualTo(1L);
assertThat(result.get("doubleField")).isEqualTo(1.1);
assertThat(result.get("boolField")).isEqualTo(false);
}

@Test
void toObjectMapShouldHandleKindNotSetValue() {
// This test verifies that KIND_NOT_SET values are handled gracefully
Value kindNotSetValue = Value.newBuilder().build(); // Default case - KIND_NOT_SET

Map<String, Value> payload = Map.of("unsetField", kindNotSetValue);

Map<String, Object> result = QdrantObjectFactory.toObjectMap(payload);

assertThat(result).hasSize(1);
assertThat(result.get("unsetField")).isNull();
}

@Test
void toObjectMapShouldThrowExceptionForNullPayload() {
assertThatThrownBy(() -> QdrantObjectFactory.toObjectMap(null)).isInstanceOf(IllegalArgumentException.class)
.hasMessage("Payload map must not be null");
}

@Test
void toObjectMapShouldHandleMixedDataTypes() {
Map<String, Value> payload = Map.of("text", Value.newBuilder().setStringValue("").build(), // empty
// string
"flag", Value.newBuilder().setBoolValue(true).build(), "nullField",
Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(), "number",
Value.newBuilder().setIntegerValue(1).build());

Map<String, Object> result = QdrantObjectFactory.toObjectMap(payload);

assertThat(result).hasSize(4);
assertThat(result.get("text")).isEqualTo("");
assertThat(result.get("flag")).isEqualTo(true);
assertThat(result.get("nullField")).isNull();
assertThat(result.get("number")).isEqualTo(1L);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,123 @@ void builderShouldHandleBooleanToggling() {
assertThat(vectorStore3).hasFieldOrPropertyWithValue("initializeSchema", true);
}

@Test
void builderShouldPreserveMockedDependencies() {
QdrantVectorStore vectorStore = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel).build();

assertThat(vectorStore).hasFieldOrPropertyWithValue("qdrantClient", this.qdrantClient);
assertThat(vectorStore).hasFieldOrPropertyWithValue("embeddingModel", this.embeddingModel);
}

@Test
void builderShouldCreateImmutableConfiguration() {
QdrantVectorStore.Builder builder = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
.collectionName("test_collection")
.initializeSchema(true);

QdrantVectorStore vectorStore1 = builder.build();

// Modify builder after first build
builder.collectionName("different_collection").initializeSchema(false);
QdrantVectorStore vectorStore2 = builder.build();

// First vector store should remain unchanged
assertThat(vectorStore1).hasFieldOrPropertyWithValue("collectionName", "test_collection");
assertThat(vectorStore1).hasFieldOrPropertyWithValue("initializeSchema", true);

// Second vector store should have new values
assertThat(vectorStore2).hasFieldOrPropertyWithValue("collectionName", "different_collection");
assertThat(vectorStore2).hasFieldOrPropertyWithValue("initializeSchema", false);
}

@Test
void builderShouldHandleNullQdrantClientCorrectly() {
assertThatThrownBy(() -> QdrantVectorStore.builder(null, this.embeddingModel))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("QdrantClient must not be null");
}

@Test
void builderShouldValidateConfigurationOnBuild() {
QdrantVectorStore.Builder builder = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel);

// Should succeed with valid configuration
assertThat(builder.build()).isNotNull();

// Should fail when trying to build with invalid configuration set later
assertThatThrownBy(() -> builder.collectionName("").build()).isInstanceOf(IllegalArgumentException.class)
.hasMessage("collectionName must not be empty");
}

@Test
void builderShouldRetainLastSetBatchingStrategy() {
TokenCountBatchingStrategy strategy1 = new TokenCountBatchingStrategy();
TokenCountBatchingStrategy strategy2 = new TokenCountBatchingStrategy();
TokenCountBatchingStrategy strategy3 = new TokenCountBatchingStrategy();

QdrantVectorStore vectorStore = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
.batchingStrategy(strategy1)
.batchingStrategy(strategy2)
.batchingStrategy(strategy3)
.build();

assertThat(vectorStore).hasFieldOrPropertyWithValue("batchingStrategy", strategy3);
}

@Test
void builderShouldHandleCollectionNameEdgeCases() {
// Test single character collection name
QdrantVectorStore vectorStore1 = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
.collectionName("a")
.build();
assertThat(vectorStore1).hasFieldOrPropertyWithValue("collectionName", "a");

// Test collection name with numbers only
QdrantVectorStore vectorStore2 = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
.collectionName("12345")
.build();
assertThat(vectorStore2).hasFieldOrPropertyWithValue("collectionName", "12345");

// Test collection name starting with number
QdrantVectorStore vectorStore3 = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
.collectionName("1collection")
.build();
assertThat(vectorStore3).hasFieldOrPropertyWithValue("collectionName", "1collection");
}

@Test
void builderShouldMaintainBuilderPattern() {
QdrantVectorStore.Builder builder = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel);

// Each method should return the builder for chaining
QdrantVectorStore.Builder result = builder.collectionName("test")
.initializeSchema(true)
.batchingStrategy(new TokenCountBatchingStrategy());

assertThat(result).isSameAs(builder);
}

@Test
void builderShouldHandleRepeatedConfigurationCalls() {
QdrantVectorStore.Builder builder = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel);

// Call configuration methods multiple times in different orders
builder.initializeSchema(true)
.collectionName("first")
.initializeSchema(false)
.collectionName("second")
.initializeSchema(true);

QdrantVectorStore vectorStore = builder.build();

// Should use the last set values
assertThat(vectorStore).hasFieldOrPropertyWithValue("collectionName", "second");
assertThat(vectorStore).hasFieldOrPropertyWithValue("initializeSchema", true);

// Verify builder can still be used after build
QdrantVectorStore anotherVectorStore = builder.collectionName("third").build();
assertThat(anotherVectorStore).hasFieldOrPropertyWithValue("collectionName", "third");
assertThat(anotherVectorStore).hasFieldOrPropertyWithValue("initializeSchema", true);
}

}