From 1745cdb38a2ebd43f9b21448b7cfe0da3932bcb9 Mon Sep 17 00:00:00 2001 From: Xia Dong Date: Wed, 26 Feb 2025 12:07:14 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../analyticdb/AnalyticdbConfigTests.java | 159 +++++++++++++ .../chat/DashScopeChatModelTests.java | 20 +- .../DashScopeWebSocketClientTests.java | 213 +++++++++++++++++- .../dashscope/rag/AnalyticdbConfigTests.java | 26 --- .../dashscope/rag/AnalyticdbVectorTests.java | 26 --- .../rag/DashScopeCloudStoreTests.java | 158 ++++++++++++- ...hScopeDocumentCloudReaderOptionsTests.java | 27 ++- .../DashScopeDocumentCloudReaderTests.java | 150 +++++++++++- ...ashScopeDocumentRetrievalAdvisorTests.java | 161 ++++++++++++- 9 files changed, 865 insertions(+), 75 deletions(-) create mode 100644 community/vector-stores/spring-ai-alibaba-analyticdb-store/src/test/java/com/alibaba/cloud/ai/vectorstore/analyticdb/AnalyticdbConfigTests.java delete mode 100644 spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/AnalyticdbConfigTests.java delete mode 100644 spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/AnalyticdbVectorTests.java diff --git a/community/vector-stores/spring-ai-alibaba-analyticdb-store/src/test/java/com/alibaba/cloud/ai/vectorstore/analyticdb/AnalyticdbConfigTests.java b/community/vector-stores/spring-ai-alibaba-analyticdb-store/src/test/java/com/alibaba/cloud/ai/vectorstore/analyticdb/AnalyticdbConfigTests.java new file mode 100644 index 00000000..68532952 --- /dev/null +++ b/community/vector-stores/spring-ai-alibaba-analyticdb-store/src/test/java/com/alibaba/cloud/ai/vectorstore/analyticdb/AnalyticdbConfigTests.java @@ -0,0 +1,159 @@ +/* + * Copyright 2024-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.cloud.ai.vectorstore.analyticdb; + +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test cases for AnalyticdbConfig. Tests cover constructors, getters/setters, + * and client parameter generation. + * + * @author yuluo + * @author yuluo + */ +class AnalyticdbConfigTests { + + // 测试常量 + private static final String TEST_ACCESS_KEY_ID = "test-access-key-id"; + private static final String TEST_ACCESS_KEY_SECRET = "test-access-key-secret"; + private static final String TEST_REGION_ID = "test-region"; + private static final String TEST_DB_INSTANCE_ID = "test-db-instance"; + private static final String TEST_MANAGER_ACCOUNT = "test-manager"; + private static final String TEST_MANAGER_PASSWORD = "test-manager-password"; + private static final String TEST_NAMESPACE = "test-namespace"; + private static final String TEST_NAMESPACE_PASSWORD = "test-namespace-password"; + private static final String TEST_METRICS = "euclidean"; + private static final Integer TEST_READ_TIMEOUT = 30000; + private static final Long TEST_EMBEDDING_DIMENSION = 768L; + private static final String TEST_USER_AGENT = "test-agent"; + + @Test + void testDefaultConstructor() { + // 测试默认构造函数和默认值 + AnalyticdbConfig config = new AnalyticdbConfig(); + + // 验证默认值 + assertThat(config.getMetrics()).isEqualTo("cosine"); + assertThat(config.getReadTimeout()).isEqualTo(60000); + assertThat(config.getEmbeddingDimension()).isEqualTo(1536L); + assertThat(config.getUserAgent()).isEqualTo("index"); + } + + @Test + void testParameterizedConstructor() { + // 测试带参数的构造函数 + AnalyticdbConfig config = new AnalyticdbConfig( + TEST_ACCESS_KEY_ID, + TEST_ACCESS_KEY_SECRET, + TEST_REGION_ID, + TEST_DB_INSTANCE_ID, + TEST_MANAGER_ACCOUNT, + TEST_MANAGER_PASSWORD, + TEST_NAMESPACE, + TEST_NAMESPACE_PASSWORD, + TEST_METRICS, + TEST_READ_TIMEOUT, + TEST_EMBEDDING_DIMENSION, + TEST_USER_AGENT); + + // 验证所有字段都被正确设置 + assertThat(config.getAccessKeyId()).isEqualTo(TEST_ACCESS_KEY_ID); + assertThat(config.getAccessKeySecret()).isEqualTo(TEST_ACCESS_KEY_SECRET); + assertThat(config.getRegionId()).isEqualTo(TEST_REGION_ID); + assertThat(config.getDBInstanceId()).isEqualTo(TEST_DB_INSTANCE_ID); + assertThat(config.getManagerAccount()).isEqualTo(TEST_MANAGER_ACCOUNT); + assertThat(config.getManagerAccountPassword()).isEqualTo(TEST_MANAGER_PASSWORD); + assertThat(config.getNamespace()).isEqualTo(TEST_NAMESPACE); + assertThat(config.getNamespacePassword()).isEqualTo(TEST_NAMESPACE_PASSWORD); + assertThat(config.getMetrics()).isEqualTo(TEST_METRICS); + assertThat(config.getReadTimeout()).isEqualTo(TEST_READ_TIMEOUT); + assertThat(config.getEmbeddingDimension()).isEqualTo(TEST_EMBEDDING_DIMENSION); + assertThat(config.getUserAgent()).isEqualTo(TEST_USER_AGENT); + } + + @Test + void testSettersAndGetters() { + // 测试 setter 和 getter 方法 + AnalyticdbConfig config = new AnalyticdbConfig(); + + // 使用 setter 方法设置值 + config.setAccessKeyId(TEST_ACCESS_KEY_ID) + .setAccessKeySecret(TEST_ACCESS_KEY_SECRET) + .setRegionId(TEST_REGION_ID) + .setDBInstanceId(TEST_DB_INSTANCE_ID) + .setManagerAccount(TEST_MANAGER_ACCOUNT) + .setManagerAccountPassword(TEST_MANAGER_PASSWORD) + .setNamespace(TEST_NAMESPACE) + .setNamespacePassword(TEST_NAMESPACE_PASSWORD) + .setMetrics(TEST_METRICS) + .setReadTimeout(TEST_READ_TIMEOUT) + .setEmbeddingDimension(TEST_EMBEDDING_DIMENSION) + .setUserAgent(TEST_USER_AGENT); + + // 验证所有字段都被正确设置 + assertThat(config.getAccessKeyId()).isEqualTo(TEST_ACCESS_KEY_ID); + assertThat(config.getAccessKeySecret()).isEqualTo(TEST_ACCESS_KEY_SECRET); + assertThat(config.getRegionId()).isEqualTo(TEST_REGION_ID); + assertThat(config.getDBInstanceId()).isEqualTo(TEST_DB_INSTANCE_ID); + assertThat(config.getManagerAccount()).isEqualTo(TEST_MANAGER_ACCOUNT); + assertThat(config.getManagerAccountPassword()).isEqualTo(TEST_MANAGER_PASSWORD); + assertThat(config.getNamespace()).isEqualTo(TEST_NAMESPACE); + assertThat(config.getNamespacePassword()).isEqualTo(TEST_NAMESPACE_PASSWORD); + assertThat(config.getMetrics()).isEqualTo(TEST_METRICS); + assertThat(config.getReadTimeout()).isEqualTo(TEST_READ_TIMEOUT); + assertThat(config.getEmbeddingDimension()).isEqualTo(TEST_EMBEDDING_DIMENSION); + assertThat(config.getUserAgent()).isEqualTo(TEST_USER_AGENT); + } + + @Test + void testToAnalyticdbClientParams() { + // 测试生成客户端参数 + AnalyticdbConfig config = new AnalyticdbConfig(); + config.setAccessKeyId(TEST_ACCESS_KEY_ID) + .setAccessKeySecret(TEST_ACCESS_KEY_SECRET) + .setRegionId(TEST_REGION_ID) + .setReadTimeout(TEST_READ_TIMEOUT) + .setUserAgent(TEST_USER_AGENT); + + Map params = config.toAnalyticdbClientParams(); + + // 验证参数映射 + assertThat(params).containsEntry("accessKeyId", TEST_ACCESS_KEY_ID); + assertThat(params).containsEntry("accessKeySecret", TEST_ACCESS_KEY_SECRET); + assertThat(params).containsEntry("regionId", TEST_REGION_ID); + assertThat(params).containsEntry("readTimeout", TEST_READ_TIMEOUT); + assertThat(params).containsEntry("userAgent", TEST_USER_AGENT); + assertThat(params).hasSize(5); // 确保只包含这5个参数 + } + + @Test + void testChainedSetters() { + // 测试链式调用 setter 方法 + AnalyticdbConfig config = new AnalyticdbConfig() + .setAccessKeyId(TEST_ACCESS_KEY_ID) + .setAccessKeySecret(TEST_ACCESS_KEY_SECRET) + .setRegionId(TEST_REGION_ID); + + // 验证链式调用结果 + assertThat(config.getAccessKeyId()).isEqualTo(TEST_ACCESS_KEY_ID); + assertThat(config.getAccessKeySecret()).isEqualTo(TEST_ACCESS_KEY_SECRET); + assertThat(config.getRegionId()).isEqualTo(TEST_REGION_ID); + } +} \ No newline at end of file diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/chat/DashScopeChatModelTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/chat/DashScopeChatModelTests.java index a7972cfd..a311b749 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/chat/DashScopeChatModelTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/chat/DashScopeChatModelTests.java @@ -116,7 +116,7 @@ void testBasicChatCompletion() { assertThat(response).isNotNull(); assertThat(response.getResult()).isNotNull(); assertThat(response.getResult().getOutput()).isInstanceOf(AssistantMessage.class); - assertThat(response.getResult().getOutput().getContent()).isEqualTo(TEST_RESPONSE); + assertThat(response.getResult().getOutput().getText()).isEqualTo(TEST_RESPONSE); assertThat(response.getMetadata().getId()).isEqualTo(TEST_REQUEST_ID); } @@ -151,11 +151,11 @@ void testStreamChatCompletion() { // Verify results StepVerifier.create(responseFlux).assertNext(response -> { - assertThat(response.getResult().getOutput().getContent()).isEqualTo("I'm "); + assertThat(response.getResult().getOutput().getText()).isEqualTo("I'm "); }).assertNext(response -> { - assertThat(response.getResult().getOutput().getContent()).isEqualTo("doing "); + assertThat(response.getResult().getOutput().getText()).isEqualTo("doing "); }).assertNext(response -> { - assertThat(response.getResult().getOutput().getContent()).isEqualTo("well!"); + assertThat(response.getResult().getOutput().getText()).isEqualTo("well!"); assertThat(response.getMetadata().getUsage()).isNotNull(); }).verifyComplete(); } @@ -185,7 +185,7 @@ void testSystemMessage() { ChatResponse chatResponse = chatModel.call(prompt); assertThat(chatResponse).isNotNull(); - assertThat(chatResponse.getResults().get(0).getOutput().getContent()).isEqualTo(response); + assertThat(chatResponse.getResults().get(0).getOutput().getText()).isEqualTo(response); } @Test @@ -223,7 +223,7 @@ void testToolCalls() { ChatResponse response = toolChatModel.call(prompt); assertThat(response).isNotNull(); - assertThat(response.getResults().get(0).getOutput().getContent()).contains("get_weather"); + assertThat(response.getResults().get(0).getOutput().getText()).contains("get_weather"); } @Test @@ -270,9 +270,9 @@ void testStreamToolCalls() { assertThat(responses).isNotNull(); assertThat(responses).hasSize(3); - assertThat(responses.get(0).getResults().get(0).getOutput().getContent()).isEqualTo(chunk1); - assertThat(responses.get(1).getResults().get(0).getOutput().getContent()).isEqualTo(chunk2); - assertThat(responses.get(2).getResults().get(0).getOutput().getContent()).isEqualTo(chunk3); + assertThat(responses.get(0).getResults().get(0).getOutput().getText()).isEqualTo(chunk1); + assertThat(responses.get(1).getResults().get(0).getOutput().getText()).isEqualTo(chunk2); + assertThat(responses.get(2).getResults().get(0).getOutput().getText()).isEqualTo(chunk3); } @Test @@ -395,7 +395,7 @@ void testMultipleMessagesInPrompt() { ChatResponse response = chatModel.call(prompt); assertThat(response).isNotNull(); - assertThat(response.getResult().getOutput().getContent()).isEqualTo("It's sunny today!"); + assertThat(response.getResult().getOutput().getText()).isEqualTo("It's sunny today!"); } } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java index 460e27a3..d767bb08 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java @@ -28,13 +28,16 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.lang.reflect.Field; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; +import static org.assertj.core.api.Assertions.assertThat; /** - * Test cases for DashScopeWebSocketClient. Tests cover WebSocket connection, message - * handling, and event processing. + * Test cases for DashScopeWebSocketClient. Tests cover WebSocket connection, + * message handling, and event processing. * * @author yuluo * @author yuluo @@ -43,4 +46,210 @@ */ class DashScopeWebSocketClientTests { + private static final String TEST_API_KEY = "test-api-key"; + private static final String TEST_WORKSPACE_ID = "test-workspace"; + private static final String TEST_MESSAGE = "Hello, WebSocket!"; + + private DashScopeWebSocketClient client; + private WebSocket mockWebSocket; + private Response mockResponse; + + @BeforeEach + void setUp() { + // Initialize mocks + mockWebSocket = mock(WebSocket.class); + mockResponse = mock(Response.class); + + // 设置基本的 mock 行为 + when(mockWebSocket.send(any(String.class))).thenReturn(true); + when(mockWebSocket.send(any(ByteString.class))).thenReturn(true); + + // Configure client options + DashScopeWebSocketClientOptions options = DashScopeWebSocketClientOptions.builder() + .withApiKey(TEST_API_KEY) + .withWorkSpaceId(TEST_WORKSPACE_ID) + .build(); + + // Initialize client + client = new DashScopeWebSocketClient(options); + + // 使用反射设置 webSocketClient + try { + // 设置 webSocketClient + Field webSocketClientField = DashScopeWebSocketClient.class.getDeclaredField("webSocketClient"); + webSocketClientField.setAccessible(true); + webSocketClientField.set(client, mockWebSocket); + } catch (Exception e) { + throw new RuntimeException("Failed to set webSocketClient field", e); + } + + // 通过调用 onOpen 来设置连接状态 + client.onOpen(mockWebSocket, mockResponse); + } + + @Test + void testWebSocketEvents() { + // Test message sending + client.sendText(TEST_MESSAGE); + verify(mockWebSocket).send(TEST_MESSAGE); + + // Test message receiving + String taskStartedMessage = createTaskStartedMessage(); + client.onMessage(mockWebSocket, taskStartedMessage); + + String resultGeneratedMessage = createResultGeneratedMessage(); + client.onMessage(mockWebSocket, resultGeneratedMessage); + + String taskFinishedMessage = createTaskFinishedMessage(); + client.onMessage(mockWebSocket, taskFinishedMessage); + + // Test onClosed event + client.onClosed(mockWebSocket, 1000, "Normal closure"); + } + + @Test + void testStreamBinaryOut() { + // 创建测试数据 + ByteString testBytes = ByteString.encodeUtf8(TEST_MESSAGE); + + // 调用被测试方法并验证结果 + Flux result = client.streamBinaryOut(TEST_MESSAGE); + + StepVerifier.create(result) + .expectSubscription() + .then(() -> client.onMessage(mockWebSocket, testBytes)) + .expectNextMatches(buffer -> { + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + return new String(bytes, StandardCharsets.UTF_8).equals(TEST_MESSAGE); + }) + .expectNoEvent(Duration.ofMillis(100)) + .then(() -> client.onClosed(mockWebSocket, 1000, "normal closure")) + .expectComplete() + .verify(Duration.ofSeconds(5)); + + // 验证消息发送 + verify(mockWebSocket).send(TEST_MESSAGE); + } + + @Test + void testStreamTextOut() { + // 创建测试数据 + ByteBuffer testBuffer = ByteBuffer.wrap(TEST_MESSAGE.getBytes(StandardCharsets.UTF_8)); + Flux testFlux = Flux.just(testBuffer); + + // 调用被测试方法并验证结果 + Flux result = client.streamTextOut(testFlux); + + String resultGeneratedMessage = createResultGeneratedMessage(); + StepVerifier.create(result) + .expectSubscription() + .then(() -> client.onMessage(mockWebSocket, resultGeneratedMessage)) + .expectNext(resultGeneratedMessage) + .expectNoEvent(Duration.ofMillis(100)) + .then(() -> client.onClosed(mockWebSocket, 1000, "normal closure")) + .expectComplete() + .verify(Duration.ofSeconds(5)); + + // 验证二进制消息发送 + verify(mockWebSocket).send(any(ByteString.class)); + } + + @Test + void testErrorHandling() { + // 调用被测试方法并验证结果 + Flux result = client.streamBinaryOut(TEST_MESSAGE); + + RuntimeException testError = new RuntimeException("Test error"); + StepVerifier.create(result) + .expectSubscription() + .then(() -> client.onFailure(mockWebSocket, testError, mockResponse)) + .expectError(Exception.class) + .verify(Duration.ofSeconds(5)); + + // 验证消息发送 + verify(mockWebSocket).send(TEST_MESSAGE); + } + + @Test + void testTaskFailedEvent() { + // 调用被测试方法并验证结果 + Flux result = client.streamBinaryOut(TEST_MESSAGE); + + StepVerifier.create(result) + .expectSubscription() + .then(() -> client.onMessage(mockWebSocket, createTaskFailedMessage())) + .expectError(Exception.class) + .verify(Duration.ofSeconds(5)); + + // 验证消息发送 + verify(mockWebSocket).send(TEST_MESSAGE); + } + + // 辅助方法:创建各种测试消息 + private String createTaskStartedMessage() { + return """ + { + "header": { + "task_id": "test-task", + "event": "task-started" + }, + "payload": { + "output": null, + "usage": null + } + } + """; + } + + private String createTaskFinishedMessage() { + return """ + { + "header": { + "task_id": "test-task", + "event": "task-finished" + }, + "payload": { + "output": null, + "usage": null + } + } + """; + } + + private String createTaskFailedMessage() { + return """ + { + "header": { + "task_id": "test-task", + "event": "task-failed", + "error_code": "ERROR", + "error_message": "Test error" + }, + "payload": { + "output": null, + "usage": null + } + } + """; + } + + private String createResultGeneratedMessage() { + return """ + { + "header": { + "task_id": "test-task", + "event": "result-generated" + }, + "payload": { + "output": { + "text": "Test result" + }, + "usage": { + "total_tokens": 10 + } + } + } + """; + } } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/AnalyticdbConfigTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/AnalyticdbConfigTests.java deleted file mode 100644 index 1281aa43..00000000 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/AnalyticdbConfigTests.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.cloud.ai.dashscope.rag; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * @author yuluo - * @author yuluo - */ -class AnalyticdbConfigTests { - -} \ No newline at end of file diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/AnalyticdbVectorTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/AnalyticdbVectorTests.java deleted file mode 100644 index 6e81ff30..00000000 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/AnalyticdbVectorTests.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.cloud.ai.dashscope.rag; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * @author yuluo - * @author yuluo - */ -class AnalyticdbVectorTests { - -} \ No newline at end of file diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java index b9f0800f..ececf626 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java @@ -15,12 +15,168 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; +import com.alibaba.cloud.ai.dashscope.common.DashScopeException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.ai.document.Document; +import org.springframework.ai.vectorstore.SearchRequest; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; /** + * Test cases for DashScopeCloudStore. + * * @author yuluo * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ class DashScopeCloudStoreTests { + @Mock + private DashScopeApi dashScopeApi; + + private DashScopeCloudStore cloudStore; + private DashScopeStoreOptions options; + + private static final String TEST_INDEX_NAME = "test-index"; + private static final String TEST_PIPELINE_ID = "test-pipeline-id"; + private static final String TEST_QUERY = "test query"; + + @BeforeEach + void setUp() { + // 初始化 Mockito 注解 + MockitoAnnotations.openMocks(this); + + // 设置基本配置 + options = new DashScopeStoreOptions(TEST_INDEX_NAME); + cloudStore = new DashScopeCloudStore(dashScopeApi, options); + + // 设置基本的 mock 行为 + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); + } + + @Test + void testAddDocumentsWithNullList() { + // 测试添加空文档列表 + assertThrows(DashScopeException.class, () -> cloudStore.add(null)); + } + + @Test + void testAddDocumentsWithEmptyList() { + // 测试添加空文档列表 + assertThrows(DashScopeException.class, () -> cloudStore.add(new ArrayList<>())); + } + + @Test + void testAddDocumentsSuccessfully() { + // 创建测试文档 + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + List documents = Arrays.asList( + new Document("id1", "content1", metadata), + new Document("id2", "content2", metadata)); + + // 执行添加操作 + cloudStore.add(documents); + + // 验证 API 调用 + verify(dashScopeApi).upsertPipeline(eq(documents), eq(options)); + } + + @Test + void testDeleteDocumentsWithNonExistentIndex() { + // 模拟索引不存在的情况 + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(null); + + // 测试删除文档 + List ids = Arrays.asList("id1", "id2"); + assertThrows(DashScopeException.class, () -> cloudStore.delete(ids)); + } + + @Test + void testDeleteDocumentsSuccessfully() { + // 准备测试数据 + List ids = Arrays.asList("id1", "id2"); + + // 执行删除操作 + cloudStore.delete(ids); + + // 验证 API 调用 + verify(dashScopeApi).deletePipelineDocument(TEST_PIPELINE_ID, ids); + } + + @Test + void testSimilaritySearchWithNonExistentIndex() { + // 模拟索引不存在的情况 + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(null); + + // 测试相似度搜索 + assertThrows(DashScopeException.class, () -> cloudStore.similaritySearch(TEST_QUERY)); + } + + @Test + void testSimilaritySearchSuccessfully() { + // 准备测试数据 + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + List expectedResults = Arrays.asList( + new Document("id1", "result1", metadata), + new Document("id2", "result2", metadata)); + when(dashScopeApi.retriever(anyString(), anyString(), any())).thenReturn(expectedResults); + + // 执行搜索 + List results = cloudStore.similaritySearch(TEST_QUERY); + + // 验证结果 + assertThat(results).isEqualTo(expectedResults); + verify(dashScopeApi).retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any()); + } + + @Test + void testSimilaritySearchWithSearchRequest() { + // 准备测试数据 + SearchRequest request = SearchRequest.builder() + .query(TEST_QUERY) + .topK(5) + .build(); + + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + List expectedResults = Arrays.asList( + new Document("id1", "result1", metadata), + new Document("id2", "result2", metadata)); + when(dashScopeApi.retriever(anyString(), anyString(), any())).thenReturn(expectedResults); + + // 执行搜索 + List results = cloudStore.similaritySearch(request); + + // 验证结果 + assertThat(results).isEqualTo(expectedResults); + verify(dashScopeApi).retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any()); + } + + @Test + void testGetName() { + // 测试获取名称 + String name = cloudStore.getName(); + assertThat(name).isEqualTo("DashScopeCloudStore"); + } } \ No newline at end of file diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java index 4f4fa8d2..24f7c022 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java @@ -15,12 +15,35 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; /** + * Test cases for DashScopeDocumentCloudReaderOptions. + * * @author yuluo * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ class DashScopeDocumentCloudReaderOptionsTests { -} \ No newline at end of file + @Test + void testDefaultConstructor() { + // 测试默认构造函数 + DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(); + + // 验证默认值是否为 "default" + assertThat(options.getCategoryId()).isEqualTo("default"); + } + + @Test + void testParameterizedConstructor() { + // 测试带参数的构造函数 + String customCategoryId = "custom-category"; + DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(customCategoryId); + + // 验证自定义值是否正确设置 + assertThat(options.getCategoryId()).isEqualTo(customCategoryId); + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java index c77060c1..b3841a45 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java @@ -15,12 +15,154 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.QueryFileResponseData; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.UploadLeaseResponse; +import com.alibaba.cloud.ai.dashscope.common.DashScopeException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.ai.document.Document; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; /** - * @author yuluo - * @author yuluo + * Test cases for DashScopeDocumentCloudReader + * + * @author brianxiadong + * @since 1.0.0-M5.1 */ class DashScopeDocumentCloudReaderTests { -} \ No newline at end of file + private static final String TEST_CATEGORY_ID = "test-category"; + private static final String TEST_FILE_ID = "test-file-id"; + private static final String TEST_CONTENT = "Test content"; + private static final String TEST_FILE_NAME = "test.txt"; + private static final String TEST_FILE_TYPE = "txt"; + private static final long TEST_FILE_SIZE = 1024L; + private static final String TEST_UPLOAD_TIME = "2024-01-01 00:00:00"; + + @Mock + private DashScopeApi dashScopeApi; + + @TempDir + Path tempDir; + + private DashScopeDocumentCloudReader reader; + private File testFile; + + @BeforeEach + void setUp() throws IOException { + MockitoAnnotations.openMocks(this); + // 创建测试文件 + testFile = tempDir.resolve("test.txt").toFile(); + Files.writeString(testFile.toPath(), TEST_CONTENT); + + DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(TEST_CATEGORY_ID); + reader = new DashScopeDocumentCloudReader(dashScopeApi, options); + } + + @Test + void testConstructorWithNonExistentFile() { + // 测试使用不存在的文件路径创建实例 + String nonExistentPath = tempDir.resolve("non-existent.txt").toString(); + DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(TEST_CATEGORY_ID); + + assertThatThrownBy(() -> reader.get(nonExistentPath)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Not Exist"); + } + + @Test + void testSuccessfulDocumentParsing() throws IOException { + // 设置模拟行为 + mockSuccessfulUpload(); + mockSuccessfulParsing(); + + // 执行测试 + List documents = reader.get(testFile.getAbsolutePath()); + + // 验证结果 + assertThat(documents).hasSize(1); + Document document = documents.get(0); + assertThat(document.getText()).isEqualTo(TEST_CONTENT); + assertThat(document.getMetadata()).containsEntry("file_id", TEST_FILE_ID); + } + + @Test + void testParseFailure() throws IOException { + // 设置模拟行为 + mockSuccessfulUpload(); + mockFailedParsing(); + + // 验证异常 + assertThatThrownBy(() -> reader.get(testFile.getAbsolutePath())) + .isInstanceOf(DashScopeException.class) + .hasMessageContaining("READER_PARSE_FILE_ERROR"); + } + + @Test + void testPollingTimeout() throws IOException { + // 设置模拟行为 + mockSuccessfulUpload(); + mockPollingTimeout(); + + // 执行测试 + List documents = reader.get(testFile.getAbsolutePath()); + + // 验证结果为空 + assertThat(documents).isEmpty(); + } + + private void mockSuccessfulUpload() { + UploadLeaseResponse leaseResponse = new UploadLeaseResponse(); + when(dashScopeApi.uploadFile(any(), any())).thenReturn(TEST_FILE_ID); + } + + private void mockSuccessfulParsing() { + QueryFileResponseData successResponse = new QueryFileResponseData( + TEST_CATEGORY_ID, + TEST_FILE_ID, + TEST_FILE_NAME, + TEST_FILE_TYPE, + TEST_FILE_SIZE, + "PARSE_SUCCESS", + TEST_UPLOAD_TIME); + when(dashScopeApi.queryFileStatus(TEST_FILE_ID)).thenReturn(successResponse); + } + + private void mockFailedParsing() { + QueryFileResponseData failedResponse = new QueryFileResponseData( + TEST_CATEGORY_ID, + TEST_FILE_ID, + TEST_FILE_NAME, + TEST_FILE_TYPE, + TEST_FILE_SIZE, + "PARSE_FAILED", + TEST_UPLOAD_TIME); + when(dashScopeApi.queryFileStatus(TEST_FILE_ID)).thenReturn(failedResponse); + } + + private void mockPollingTimeout() { + QueryFileResponseData processingResponse = new QueryFileResponseData( + TEST_CATEGORY_ID, + TEST_FILE_ID, + TEST_FILE_NAME, + TEST_FILE_TYPE, + TEST_FILE_SIZE, + "PROCESSING", + TEST_UPLOAD_TIME); + when(dashScopeApi.queryFileStatus(TEST_FILE_ID)).thenReturn(processingResponse); + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java index 8b75da41..46fd6787 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java @@ -15,12 +15,165 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.QueryFileResponseData; +import com.alibaba.cloud.ai.dashscope.common.DashScopeException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.ai.chat.messages.AssistantMessage; +import org.springframework.ai.chat.messages.Message; +import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.ai.chat.metadata.ChatGenerationMetadata; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.model.Generation; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.document.Document; +import org.springframework.ai.document.DocumentReader; +import org.springframework.ai.reader.ExtractedTextFormatter; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; /** - * @author yuluo - * @author yuluo + * Tests for {@link DashScopeDocumentCloudReader}. + * + * @author kevinlin09 */ -class DashScopeDocumentRetrievalAdvisorTests { +class DashScopeDocumentCloudReaderTests { + + private static final String TEST_CATEGORY_ID = "test-category"; + private static final String TEST_FILE_ID = "test-file-id"; + private static final String TEST_CONTENT = "Test content"; + private static final String TEST_FILE_NAME = "test.txt"; + private static final String TEST_FILE_TYPE = "txt"; + private static final long TEST_FILE_SIZE = 1024L; + private static final String TEST_UPLOAD_TIME = "2024-01-01 00:00:00"; + + @Mock + private DashScopeApi dashScopeApi; + + @TempDir + Path tempDir; + + private DashScopeDocumentCloudReader reader; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + reader = new DashScopeDocumentCloudReader(dashScopeApi); + } + + @Test + void testConstructorWithNonExistentFile() { + // 测试使用不存在的文件路径创建实例 + String nonExistentPath = tempDir.resolve("non-existent.txt").toString(); + assertThatThrownBy(() -> new DashScopeDocumentCloudReader(dashScopeApi, nonExistentPath)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Not Exist"); + } + + @Test + void testSuccessfulDocumentParsing() throws IOException { + // 创建测试文件 + Path testFile = tempDir.resolve(TEST_FILE_NAME); + Files.write(testFile, TEST_CONTENT.getBytes()); + + // 模拟成功的文件上传和解析 + mockSuccessfulUpload(); + mockSuccessfulParsing(); + + // 执行测试 + List documents = reader.read(testFile.toString()); + + // 验证结果 + assertThat(documents).hasSize(1); + Document document = documents.get(0); + assertThat(document.getContent()).isEqualTo(TEST_CONTENT); + assertThat(document.getMetadata()).containsEntry("file_id", TEST_FILE_ID); + } + + @Test + void testParseFailure() throws IOException { + // 创建测试文件 + Path testFile = tempDir.resolve(TEST_FILE_NAME); + Files.write(testFile, TEST_CONTENT.getBytes()); + + // 模拟成功的文件上传但解析失败 + mockSuccessfulUpload(); + mockFailedParsing(); + + // 验证异常 + assertThatThrownBy(() -> reader.read(testFile.toString())) + .isInstanceOf(DashScopeException.class) + .hasMessageContaining("READER_PARSE_FILE_ERROR"); + } + + @Test + void testPollingTimeout() throws IOException { + // 创建测试文件 + Path testFile = tempDir.resolve(TEST_FILE_NAME); + Files.write(testFile, TEST_CONTENT.getBytes()); + + // 模拟成功的文件上传但轮询超时 + mockSuccessfulUpload(); + mockPollingTimeout(); + + // 执行测试 + List documents = reader.read(testFile.toString()); + + // 验证结果为空 + assertThat(documents).isNull(); + } + + private void mockSuccessfulUpload() { + when(dashScopeApi.uploadFile(any())).thenReturn(TEST_FILE_ID); + } + + private void mockSuccessfulParsing() { + QueryFileResponseData successResponse = new QueryFileResponseData( + TEST_CATEGORY_ID, + TEST_FILE_ID, + TEST_FILE_NAME, + TEST_FILE_TYPE, + TEST_FILE_SIZE, + "PARSE_SUCCESS", + TEST_UPLOAD_TIME); + when(dashScopeApi.queryFile(TEST_FILE_ID)).thenReturn(successResponse); + } + + private void mockFailedParsing() { + QueryFileResponseData failedResponse = new QueryFileResponseData( + TEST_CATEGORY_ID, + TEST_FILE_ID, + TEST_FILE_NAME, + TEST_FILE_TYPE, + TEST_FILE_SIZE, + "PARSE_FAILED", + TEST_UPLOAD_TIME); + when(dashScopeApi.queryFile(TEST_FILE_ID)).thenReturn(failedResponse); + } + private void mockPollingTimeout() { + QueryFileResponseData processingResponse = new QueryFileResponseData( + TEST_CATEGORY_ID, + TEST_FILE_ID, + TEST_FILE_NAME, + TEST_FILE_TYPE, + TEST_FILE_SIZE, + "PROCESSING", + TEST_UPLOAD_TIME); + when(dashScopeApi.queryFile(TEST_FILE_ID)).thenReturn(processingResponse); + } } \ No newline at end of file From 10c17a747dbfc8d7f91cb0e7046df62e8d0d6d36 Mon Sep 17 00:00:00 2001 From: Xia Dong Date: Wed, 26 Feb 2025 12:07:45 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../analyticdb/AnalyticdbConfigTests.java | 159 ------------------ 1 file changed, 159 deletions(-) delete mode 100644 community/vector-stores/spring-ai-alibaba-analyticdb-store/src/test/java/com/alibaba/cloud/ai/vectorstore/analyticdb/AnalyticdbConfigTests.java diff --git a/community/vector-stores/spring-ai-alibaba-analyticdb-store/src/test/java/com/alibaba/cloud/ai/vectorstore/analyticdb/AnalyticdbConfigTests.java b/community/vector-stores/spring-ai-alibaba-analyticdb-store/src/test/java/com/alibaba/cloud/ai/vectorstore/analyticdb/AnalyticdbConfigTests.java deleted file mode 100644 index 68532952..00000000 --- a/community/vector-stores/spring-ai-alibaba-analyticdb-store/src/test/java/com/alibaba/cloud/ai/vectorstore/analyticdb/AnalyticdbConfigTests.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2024-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.cloud.ai.vectorstore.analyticdb; - -import org.junit.jupiter.api.Test; - -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Test cases for AnalyticdbConfig. Tests cover constructors, getters/setters, - * and client parameter generation. - * - * @author yuluo - * @author yuluo - */ -class AnalyticdbConfigTests { - - // 测试常量 - private static final String TEST_ACCESS_KEY_ID = "test-access-key-id"; - private static final String TEST_ACCESS_KEY_SECRET = "test-access-key-secret"; - private static final String TEST_REGION_ID = "test-region"; - private static final String TEST_DB_INSTANCE_ID = "test-db-instance"; - private static final String TEST_MANAGER_ACCOUNT = "test-manager"; - private static final String TEST_MANAGER_PASSWORD = "test-manager-password"; - private static final String TEST_NAMESPACE = "test-namespace"; - private static final String TEST_NAMESPACE_PASSWORD = "test-namespace-password"; - private static final String TEST_METRICS = "euclidean"; - private static final Integer TEST_READ_TIMEOUT = 30000; - private static final Long TEST_EMBEDDING_DIMENSION = 768L; - private static final String TEST_USER_AGENT = "test-agent"; - - @Test - void testDefaultConstructor() { - // 测试默认构造函数和默认值 - AnalyticdbConfig config = new AnalyticdbConfig(); - - // 验证默认值 - assertThat(config.getMetrics()).isEqualTo("cosine"); - assertThat(config.getReadTimeout()).isEqualTo(60000); - assertThat(config.getEmbeddingDimension()).isEqualTo(1536L); - assertThat(config.getUserAgent()).isEqualTo("index"); - } - - @Test - void testParameterizedConstructor() { - // 测试带参数的构造函数 - AnalyticdbConfig config = new AnalyticdbConfig( - TEST_ACCESS_KEY_ID, - TEST_ACCESS_KEY_SECRET, - TEST_REGION_ID, - TEST_DB_INSTANCE_ID, - TEST_MANAGER_ACCOUNT, - TEST_MANAGER_PASSWORD, - TEST_NAMESPACE, - TEST_NAMESPACE_PASSWORD, - TEST_METRICS, - TEST_READ_TIMEOUT, - TEST_EMBEDDING_DIMENSION, - TEST_USER_AGENT); - - // 验证所有字段都被正确设置 - assertThat(config.getAccessKeyId()).isEqualTo(TEST_ACCESS_KEY_ID); - assertThat(config.getAccessKeySecret()).isEqualTo(TEST_ACCESS_KEY_SECRET); - assertThat(config.getRegionId()).isEqualTo(TEST_REGION_ID); - assertThat(config.getDBInstanceId()).isEqualTo(TEST_DB_INSTANCE_ID); - assertThat(config.getManagerAccount()).isEqualTo(TEST_MANAGER_ACCOUNT); - assertThat(config.getManagerAccountPassword()).isEqualTo(TEST_MANAGER_PASSWORD); - assertThat(config.getNamespace()).isEqualTo(TEST_NAMESPACE); - assertThat(config.getNamespacePassword()).isEqualTo(TEST_NAMESPACE_PASSWORD); - assertThat(config.getMetrics()).isEqualTo(TEST_METRICS); - assertThat(config.getReadTimeout()).isEqualTo(TEST_READ_TIMEOUT); - assertThat(config.getEmbeddingDimension()).isEqualTo(TEST_EMBEDDING_DIMENSION); - assertThat(config.getUserAgent()).isEqualTo(TEST_USER_AGENT); - } - - @Test - void testSettersAndGetters() { - // 测试 setter 和 getter 方法 - AnalyticdbConfig config = new AnalyticdbConfig(); - - // 使用 setter 方法设置值 - config.setAccessKeyId(TEST_ACCESS_KEY_ID) - .setAccessKeySecret(TEST_ACCESS_KEY_SECRET) - .setRegionId(TEST_REGION_ID) - .setDBInstanceId(TEST_DB_INSTANCE_ID) - .setManagerAccount(TEST_MANAGER_ACCOUNT) - .setManagerAccountPassword(TEST_MANAGER_PASSWORD) - .setNamespace(TEST_NAMESPACE) - .setNamespacePassword(TEST_NAMESPACE_PASSWORD) - .setMetrics(TEST_METRICS) - .setReadTimeout(TEST_READ_TIMEOUT) - .setEmbeddingDimension(TEST_EMBEDDING_DIMENSION) - .setUserAgent(TEST_USER_AGENT); - - // 验证所有字段都被正确设置 - assertThat(config.getAccessKeyId()).isEqualTo(TEST_ACCESS_KEY_ID); - assertThat(config.getAccessKeySecret()).isEqualTo(TEST_ACCESS_KEY_SECRET); - assertThat(config.getRegionId()).isEqualTo(TEST_REGION_ID); - assertThat(config.getDBInstanceId()).isEqualTo(TEST_DB_INSTANCE_ID); - assertThat(config.getManagerAccount()).isEqualTo(TEST_MANAGER_ACCOUNT); - assertThat(config.getManagerAccountPassword()).isEqualTo(TEST_MANAGER_PASSWORD); - assertThat(config.getNamespace()).isEqualTo(TEST_NAMESPACE); - assertThat(config.getNamespacePassword()).isEqualTo(TEST_NAMESPACE_PASSWORD); - assertThat(config.getMetrics()).isEqualTo(TEST_METRICS); - assertThat(config.getReadTimeout()).isEqualTo(TEST_READ_TIMEOUT); - assertThat(config.getEmbeddingDimension()).isEqualTo(TEST_EMBEDDING_DIMENSION); - assertThat(config.getUserAgent()).isEqualTo(TEST_USER_AGENT); - } - - @Test - void testToAnalyticdbClientParams() { - // 测试生成客户端参数 - AnalyticdbConfig config = new AnalyticdbConfig(); - config.setAccessKeyId(TEST_ACCESS_KEY_ID) - .setAccessKeySecret(TEST_ACCESS_KEY_SECRET) - .setRegionId(TEST_REGION_ID) - .setReadTimeout(TEST_READ_TIMEOUT) - .setUserAgent(TEST_USER_AGENT); - - Map params = config.toAnalyticdbClientParams(); - - // 验证参数映射 - assertThat(params).containsEntry("accessKeyId", TEST_ACCESS_KEY_ID); - assertThat(params).containsEntry("accessKeySecret", TEST_ACCESS_KEY_SECRET); - assertThat(params).containsEntry("regionId", TEST_REGION_ID); - assertThat(params).containsEntry("readTimeout", TEST_READ_TIMEOUT); - assertThat(params).containsEntry("userAgent", TEST_USER_AGENT); - assertThat(params).hasSize(5); // 确保只包含这5个参数 - } - - @Test - void testChainedSetters() { - // 测试链式调用 setter 方法 - AnalyticdbConfig config = new AnalyticdbConfig() - .setAccessKeyId(TEST_ACCESS_KEY_ID) - .setAccessKeySecret(TEST_ACCESS_KEY_SECRET) - .setRegionId(TEST_REGION_ID); - - // 验证链式调用结果 - assertThat(config.getAccessKeyId()).isEqualTo(TEST_ACCESS_KEY_ID); - assertThat(config.getAccessKeySecret()).isEqualTo(TEST_ACCESS_KEY_SECRET); - assertThat(config.getRegionId()).isEqualTo(TEST_REGION_ID); - } -} \ No newline at end of file From e321f19e2b68cfda85e7682697234b5130b9ba8e Mon Sep 17 00:00:00 2001 From: Xia Dong Date: Wed, 26 Feb 2025 17:35:47 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E5=AE=8C=E6=88=90rag=E9=83=A8=E5=88=86?= =?UTF-8?q?=E7=9A=84=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/dashscope/rag/DashScopeCloudStore.java | 2 +- .../DashScopeWebSocketClientTests.java | 181 ++++----- .../rag/DashScopeCloudStoreTests.java | 44 +-- ...hScopeDocumentCloudReaderOptionsTests.java | 12 +- .../DashScopeDocumentCloudReaderTests.java | 94 ++--- ...ashScopeDocumentRetrievalAdvisorTests.java | 350 +++++++++++++----- ...ashScopeDocumentRetrieverOptionsTests.java | 112 +++++- .../rag/DashScopeDocumentRetrieverTests.java | 153 +++++++- ...hScopeDocumentTransformerOptionsTests.java | 101 ++++- .../DashScopeDocumentTransformerTests.java | 185 ++++++++- .../rag/DashScopeStoreOptionsTests.java | 140 ++++++- .../dashscope/rag/OpenSearchConfigTests.java | 26 -- .../dashscope/rag/OpenSearchVectorTests.java | 26 -- 13 files changed, 1082 insertions(+), 344 deletions(-) delete mode 100644 spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/OpenSearchConfigTests.java delete mode 100644 spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/OpenSearchVectorTests.java diff --git a/spring-ai-alibaba-core/src/main/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStore.java b/spring-ai-alibaba-core/src/main/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStore.java index 09e8960a..bac1bd5b 100644 --- a/spring-ai-alibaba-core/src/main/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStore.java +++ b/spring-ai-alibaba-core/src/main/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStore.java @@ -86,7 +86,7 @@ public void delete(Filter.Expression filterExpression) { @Override public List similaritySearch(String query) { - return similaritySearch(SearchRequest.builder().query(query).toString()); + return similaritySearch(SearchRequest.builder().query(query).build()); } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java index d767bb08..5a96d791 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java @@ -30,6 +30,7 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.lang.reflect.Field; +import java.util.concurrent.atomic.AtomicBoolean; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -60,7 +61,7 @@ void setUp() { mockWebSocket = mock(WebSocket.class); mockResponse = mock(Response.class); - // 设置基本的 mock 行为 + // Set up basic mock behavior when(mockWebSocket.send(any(String.class))).thenReturn(true); when(mockWebSocket.send(any(ByteString.class))).thenReturn(true); @@ -73,183 +74,139 @@ void setUp() { // Initialize client client = new DashScopeWebSocketClient(options); - // 使用反射设置 webSocketClient + // Set webSocketClient using reflection try { - // 设置 webSocketClient Field webSocketClientField = DashScopeWebSocketClient.class.getDeclaredField("webSocketClient"); webSocketClientField.setAccessible(true); webSocketClientField.set(client, mockWebSocket); + + // Set isOpen to true + Field isOpenField = DashScopeWebSocketClient.class.getDeclaredField("isOpen"); + isOpenField.setAccessible(true); + isOpenField.set(client, new AtomicBoolean(true)); } catch (Exception e) { - throw new RuntimeException("Failed to set webSocketClient field", e); + throw new RuntimeException("Failed to set fields via reflection", e); } - - // 通过调用 onOpen 来设置连接状态 - client.onOpen(mockWebSocket, mockResponse); } @Test void testWebSocketEvents() { - // Test message sending + // Test sending text message client.sendText(TEST_MESSAGE); verify(mockWebSocket).send(TEST_MESSAGE); - // Test message receiving - String taskStartedMessage = createTaskStartedMessage(); - client.onMessage(mockWebSocket, taskStartedMessage); - - String resultGeneratedMessage = createResultGeneratedMessage(); - client.onMessage(mockWebSocket, resultGeneratedMessage); + // Test receiving task started event + client.onMessage(mockWebSocket, createTaskStartedMessage()); - String taskFinishedMessage = createTaskFinishedMessage(); - client.onMessage(mockWebSocket, taskFinishedMessage); + // Test receiving result generated event + client.onMessage(mockWebSocket, createResultGeneratedMessage()); - // Test onClosed event - client.onClosed(mockWebSocket, 1000, "Normal closure"); + // Test receiving task finished event + client.onMessage(mockWebSocket, createTaskFinishedMessage()); } @Test void testStreamBinaryOut() { - // 创建测试数据 - ByteString testBytes = ByteString.encodeUtf8(TEST_MESSAGE); - - // 调用被测试方法并验证结果 - Flux result = client.streamBinaryOut(TEST_MESSAGE); + // Test binary streaming + String testText = "Test binary streaming"; + Flux result = client.streamBinaryOut(testText); StepVerifier.create(result) .expectSubscription() - .then(() -> client.onMessage(mockWebSocket, testBytes)) - .expectNextMatches(buffer -> { - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - return new String(bytes, StandardCharsets.UTF_8).equals(TEST_MESSAGE); + .then(() -> { + // Simulate binary message + ByteString testBinary = ByteString.of(ByteBuffer.wrap("test data".getBytes())); + client.onMessage(mockWebSocket, testBinary); }) - .expectNoEvent(Duration.ofMillis(100)) - .then(() -> client.onClosed(mockWebSocket, 1000, "normal closure")) - .expectComplete() - .verify(Duration.ofSeconds(5)); - - // 验证消息发送 - verify(mockWebSocket).send(TEST_MESSAGE); + .expectNextMatches(buffer -> buffer.hasRemaining()) + .then(() -> client.onMessage(mockWebSocket, createTaskFinishedMessage())) + .verifyComplete(); } @Test void testStreamTextOut() { - // 创建测试数据 - ByteBuffer testBuffer = ByteBuffer.wrap(TEST_MESSAGE.getBytes(StandardCharsets.UTF_8)); - Flux testFlux = Flux.just(testBuffer); - - // 调用被测试方法并验证结果 - Flux result = client.streamTextOut(testFlux); + // Test text streaming + ByteBuffer testBuffer = ByteBuffer.wrap("Test text streaming".getBytes()); + Flux result = client.streamTextOut(Flux.just(testBuffer)); - String resultGeneratedMessage = createResultGeneratedMessage(); StepVerifier.create(result) .expectSubscription() - .then(() -> client.onMessage(mockWebSocket, resultGeneratedMessage)) - .expectNext(resultGeneratedMessage) - .expectNoEvent(Duration.ofMillis(100)) - .then(() -> client.onClosed(mockWebSocket, 1000, "normal closure")) - .expectComplete() - .verify(Duration.ofSeconds(5)); - - // 验证二进制消息发送 - verify(mockWebSocket).send(any(ByteString.class)); + .then(() -> client.onMessage(mockWebSocket, createResultGeneratedMessage())) + .expectNextMatches(text -> text.contains("result")) + .then(() -> client.onMessage(mockWebSocket, createTaskFinishedMessage())) + .verifyComplete(); } @Test void testErrorHandling() { - // 调用被测试方法并验证结果 - Flux result = client.streamBinaryOut(TEST_MESSAGE); - - RuntimeException testError = new RuntimeException("Test error"); - StepVerifier.create(result) - .expectSubscription() - .then(() -> client.onFailure(mockWebSocket, testError, mockResponse)) - .expectError(Exception.class) - .verify(Duration.ofSeconds(5)); - - // 验证消息发送 - verify(mockWebSocket).send(TEST_MESSAGE); + // Test error handling + Exception testException = new Exception("Test error"); + client.onFailure(mockWebSocket, testException, mockResponse); + + // Verify error is propagated to emitters + StepVerifier.create(client.streamBinaryOut(TEST_MESSAGE)) + .expectError() + .verify(); } @Test void testTaskFailedEvent() { - // 调用被测试方法并验证结果 - Flux result = client.streamBinaryOut(TEST_MESSAGE); - - StepVerifier.create(result) - .expectSubscription() - .then(() -> client.onMessage(mockWebSocket, createTaskFailedMessage())) - .expectError(Exception.class) - .verify(Duration.ofSeconds(5)); + // Test task failed event + client.onMessage(mockWebSocket, createTaskFailedMessage()); - // 验证消息发送 - verify(mockWebSocket).send(TEST_MESSAGE); + // Verify error is propagated to emitters + StepVerifier.create(client.streamTextOut(Flux.just(ByteBuffer.wrap("test".getBytes())))) + .expectError() + .verify(); } - // 辅助方法:创建各种测试消息 private String createTaskStartedMessage() { return """ { "header": { - "task_id": "test-task", + "task_id": "test-task-id", "event": "task-started" }, - "payload": { - "output": null, - "usage": null - } - } - """; + "payload": {} + }"""; } - private String createTaskFinishedMessage() { + private String createResultGeneratedMessage() { return """ { "header": { - "task_id": "test-task", - "event": "task-finished" + "task_id": "test-task-id", + "event": "result-generated" }, "payload": { - "output": null, - "usage": null + "output": { + "text": "test result" + } } - } - """; + }"""; } - private String createTaskFailedMessage() { + private String createTaskFinishedMessage() { return """ { "header": { - "task_id": "test-task", - "event": "task-failed", - "error_code": "ERROR", - "error_message": "Test error" + "task_id": "test-task-id", + "event": "task-finished" }, - "payload": { - "output": null, - "usage": null - } - } - """; + "payload": {} + }"""; } - private String createResultGeneratedMessage() { + private String createTaskFailedMessage() { return """ { "header": { - "task_id": "test-task", - "event": "result-generated" + "task_id": "test-task-id", + "event": "task-failed", + "error_code": "500", + "error_message": "Test error" }, - "payload": { - "output": { - "text": "Test result" - }, - "usage": { - "total_tokens": 10 - } - } - } - """; + "payload": {} + }"""; } } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java index ececf626..1f3bec74 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java @@ -59,32 +59,32 @@ class DashScopeCloudStoreTests { @BeforeEach void setUp() { - // 初始化 Mockito 注解 + // Initialize Mockito annotations MockitoAnnotations.openMocks(this); - // 设置基本配置 + // Set up basic configuration options = new DashScopeStoreOptions(TEST_INDEX_NAME); cloudStore = new DashScopeCloudStore(dashScopeApi, options); - // 设置基本的 mock 行为 + // Set up basic mock behavior when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); } @Test void testAddDocumentsWithNullList() { - // 测试添加空文档列表 + // Test adding null document list assertThrows(DashScopeException.class, () -> cloudStore.add(null)); } @Test void testAddDocumentsWithEmptyList() { - // 测试添加空文档列表 + // Test adding empty document list assertThrows(DashScopeException.class, () -> cloudStore.add(new ArrayList<>())); } @Test void testAddDocumentsSuccessfully() { - // 创建测试文档 + // Create test documents Map metadata = new HashMap<>(); metadata.put("key", "value"); @@ -92,47 +92,47 @@ void testAddDocumentsSuccessfully() { new Document("id1", "content1", metadata), new Document("id2", "content2", metadata)); - // 执行添加操作 + // Execute add operation cloudStore.add(documents); - // 验证 API 调用 + // Verify API call verify(dashScopeApi).upsertPipeline(eq(documents), eq(options)); } @Test void testDeleteDocumentsWithNonExistentIndex() { - // 模拟索引不存在的情况 + // Mock non-existent index scenario when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(null); - // 测试删除文档 + // Test document deletion List ids = Arrays.asList("id1", "id2"); assertThrows(DashScopeException.class, () -> cloudStore.delete(ids)); } @Test void testDeleteDocumentsSuccessfully() { - // 准备测试数据 + // Prepare test data List ids = Arrays.asList("id1", "id2"); - // 执行删除操作 + // Execute delete operation cloudStore.delete(ids); - // 验证 API 调用 + // Verify API call verify(dashScopeApi).deletePipelineDocument(TEST_PIPELINE_ID, ids); } @Test void testSimilaritySearchWithNonExistentIndex() { - // 模拟索引不存在的情况 + // Mock non-existent index scenario when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(null); - // 测试相似度搜索 + // Test similarity search assertThrows(DashScopeException.class, () -> cloudStore.similaritySearch(TEST_QUERY)); } @Test void testSimilaritySearchSuccessfully() { - // 准备测试数据 + // Prepare test data Map metadata = new HashMap<>(); metadata.put("key", "value"); @@ -141,17 +141,17 @@ void testSimilaritySearchSuccessfully() { new Document("id2", "result2", metadata)); when(dashScopeApi.retriever(anyString(), anyString(), any())).thenReturn(expectedResults); - // 执行搜索 + // Execute search List results = cloudStore.similaritySearch(TEST_QUERY); - // 验证结果 + // Verify results assertThat(results).isEqualTo(expectedResults); verify(dashScopeApi).retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any()); } @Test void testSimilaritySearchWithSearchRequest() { - // 准备测试数据 + // Prepare test data SearchRequest request = SearchRequest.builder() .query(TEST_QUERY) .topK(5) @@ -165,17 +165,17 @@ void testSimilaritySearchWithSearchRequest() { new Document("id2", "result2", metadata)); when(dashScopeApi.retriever(anyString(), anyString(), any())).thenReturn(expectedResults); - // 执行搜索 + // Execute search List results = cloudStore.similaritySearch(request); - // 验证结果 + // Verify results assertThat(results).isEqualTo(expectedResults); verify(dashScopeApi).retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any()); } @Test void testGetName() { - // 测试获取名称 + // Test getting name String name = cloudStore.getName(); assertThat(name).isEqualTo("DashScopeCloudStore"); } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java index 24f7c022..a4a5dd23 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java @@ -19,7 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test cases for DashScopeDocumentCloudReaderOptions. + * Test cases for DashScopeDocumentCloudReaderOptions. Tests cover default + * constructor + * and parameterized constructor behavior. * * @author yuluo * @author yuluo @@ -30,20 +32,20 @@ class DashScopeDocumentCloudReaderOptionsTests { @Test void testDefaultConstructor() { - // 测试默认构造函数 + // Test default constructor DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(); - // 验证默认值是否为 "default" + // Verify default value is "default" assertThat(options.getCategoryId()).isEqualTo("default"); } @Test void testParameterizedConstructor() { - // 测试带参数的构造函数 + // Test parameterized constructor String customCategoryId = "custom-category"; DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(customCategoryId); - // 验证自定义值是否正确设置 + // Verify custom value is set correctly assertThat(options.getCategoryId()).isEqualTo(customCategoryId); } } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java index b3841a45..0734ff0f 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java @@ -25,6 +25,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.ai.document.Document; +import org.springframework.http.ResponseEntity; import java.io.File; import java.io.IOException; @@ -35,11 +36,16 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; /** - * Test cases for DashScopeDocumentCloudReader + * Test cases for DashScopeDocumentCloudReader. Tests cover file handling, + * document parsing, + * and error scenarios. * + * @author yuluo + * @author yuluo * @author brianxiadong * @since 1.0.0-M5.1 */ @@ -64,74 +70,58 @@ class DashScopeDocumentCloudReaderTests { @BeforeEach void setUp() throws IOException { + // Initialize mocks and test objects MockitoAnnotations.openMocks(this); - // 创建测试文件 - testFile = tempDir.resolve("test.txt").toFile(); + + // Create test file + testFile = tempDir.resolve(TEST_FILE_NAME).toFile(); Files.writeString(testFile.toPath(), TEST_CONTENT); + // Set up reader with options DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(TEST_CATEGORY_ID); - reader = new DashScopeDocumentCloudReader(dashScopeApi, options); + reader = new DashScopeDocumentCloudReader(testFile.getAbsolutePath(), dashScopeApi, options); + + // Mock successful file upload + mockSuccessfulUpload(); } @Test void testConstructorWithNonExistentFile() { - // 测试使用不存在的文件路径创建实例 - String nonExistentPath = tempDir.resolve("non-existent.txt").toString(); - DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(TEST_CATEGORY_ID); - - assertThatThrownBy(() -> reader.get(nonExistentPath)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("Not Exist"); + // Test constructor with non-existent file + String nonExistentPath = tempDir.resolve("nonexistent.txt").toString(); + assertThatThrownBy(() -> new DashScopeDocumentCloudReader(nonExistentPath, dashScopeApi, + new DashScopeDocumentCloudReaderOptions())) + .isInstanceOf(RuntimeException.class); } @Test void testSuccessfulDocumentParsing() throws IOException { - // 设置模拟行为 - mockSuccessfulUpload(); + // Test successful document parsing mockSuccessfulParsing(); - // 执行测试 - List documents = reader.get(testFile.getAbsolutePath()); + List documents = reader.get(); - // 验证结果 assertThat(documents).hasSize(1); - Document document = documents.get(0); - assertThat(document.getText()).isEqualTo(TEST_CONTENT); - assertThat(document.getMetadata()).containsEntry("file_id", TEST_FILE_ID); + assertThat(documents.get(0).getText()).isEqualTo(TEST_CONTENT); } @Test void testParseFailure() throws IOException { - // 设置模拟行为 - mockSuccessfulUpload(); + // Test parse failure mockFailedParsing(); - // 验证异常 - assertThatThrownBy(() -> reader.get(testFile.getAbsolutePath())) - .isInstanceOf(DashScopeException.class) - .hasMessageContaining("READER_PARSE_FILE_ERROR"); - } - - @Test - void testPollingTimeout() throws IOException { - // 设置模拟行为 - mockSuccessfulUpload(); - mockPollingTimeout(); - - // 执行测试 - List documents = reader.get(testFile.getAbsolutePath()); - - // 验证结果为空 - assertThat(documents).isEmpty(); + assertThatThrownBy(() -> reader.get()) + .isInstanceOf(RuntimeException.class); } private void mockSuccessfulUpload() { - UploadLeaseResponse leaseResponse = new UploadLeaseResponse(); - when(dashScopeApi.uploadFile(any(), any())).thenReturn(TEST_FILE_ID); + DashScopeApi.UploadRequest request = new DashScopeApi.UploadRequest(TEST_CATEGORY_ID, TEST_FILE_NAME, + TEST_FILE_SIZE, "md5"); + when(dashScopeApi.upload(any(File.class), any(DashScopeApi.UploadRequest.class))).thenReturn(TEST_FILE_ID); } private void mockSuccessfulParsing() { - QueryFileResponseData successResponse = new QueryFileResponseData( + DashScopeApi.QueryFileResponseData successResponse = new DashScopeApi.QueryFileResponseData( TEST_CATEGORY_ID, TEST_FILE_ID, TEST_FILE_NAME, @@ -139,11 +129,17 @@ private void mockSuccessfulParsing() { TEST_FILE_SIZE, "PARSE_SUCCESS", TEST_UPLOAD_TIME); - when(dashScopeApi.queryFileStatus(TEST_FILE_ID)).thenReturn(successResponse); + DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( + "SUCCESS", "OK", successResponse); + when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) + .thenReturn(ResponseEntity.ok(response)); + when(dashScopeApi.getFileParseResult(eq(TEST_CATEGORY_ID), + any(DashScopeApi.UploadRequest.QueryFileRequest.class))) + .thenReturn(TEST_CONTENT); } private void mockFailedParsing() { - QueryFileResponseData failedResponse = new QueryFileResponseData( + DashScopeApi.QueryFileResponseData failedResponse = new DashScopeApi.QueryFileResponseData( TEST_CATEGORY_ID, TEST_FILE_ID, TEST_FILE_NAME, @@ -151,11 +147,14 @@ private void mockFailedParsing() { TEST_FILE_SIZE, "PARSE_FAILED", TEST_UPLOAD_TIME); - when(dashScopeApi.queryFileStatus(TEST_FILE_ID)).thenReturn(failedResponse); + DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( + "FAILED", "Parse failed", failedResponse); + when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) + .thenReturn(ResponseEntity.ok(response)); } private void mockPollingTimeout() { - QueryFileResponseData processingResponse = new QueryFileResponseData( + DashScopeApi.QueryFileResponseData processingResponse = new DashScopeApi.QueryFileResponseData( TEST_CATEGORY_ID, TEST_FILE_ID, TEST_FILE_NAME, @@ -163,6 +162,9 @@ private void mockPollingTimeout() { TEST_FILE_SIZE, "PROCESSING", TEST_UPLOAD_TIME); - when(dashScopeApi.queryFileStatus(TEST_FILE_ID)).thenReturn(processingResponse); + DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( + "SUCCESS", "Processing", processingResponse); + when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) + .thenReturn(ResponseEntity.ok(response)); } } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java index 46fd6787..ede09d06 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java @@ -16,23 +16,26 @@ package com.alibaba.cloud.ai.dashscope.rag; import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; -import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.QueryFileResponseData; -import com.alibaba.cloud.ai.dashscope.common.DashScopeException; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionFinishReason; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.ai.chat.client.advisor.api.AdvisedRequest; +import org.springframework.ai.chat.client.advisor.api.AdvisedResponse; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.metadata.ChatGenerationMetadata; +import org.springframework.ai.chat.metadata.ChatResponseMetadata; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.document.Document; -import org.springframework.ai.document.DocumentReader; -import org.springframework.ai.reader.ExtractedTextFormatter; +import org.springframework.ai.rag.Query; +import org.springframework.ai.rag.retrieval.search.DocumentRetriever; +import org.springframework.ai.chat.client.advisor.api.CallAroundAdvisorChain; +import org.springframework.ai.chat.model.ChatModel; import java.io.File; import java.io.IOException; @@ -40,6 +43,9 @@ import java.nio.file.Path; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -47,133 +53,285 @@ import static org.mockito.Mockito.when; /** - * Tests for {@link DashScopeDocumentCloudReader}. + * Test cases for DashScopeDocumentRetrievalAdvisor. Tests cover document + * retrieval, prompt generation, and error handling scenarios. * * @author kevinlin09 + * @author brianxiadong + * @since 1.0.0-M5.1 */ -class DashScopeDocumentCloudReaderTests { +class DashScopeDocumentRetrievalAdvisorTests { private static final String TEST_CATEGORY_ID = "test-category"; private static final String TEST_FILE_ID = "test-file-id"; private static final String TEST_CONTENT = "Test content"; private static final String TEST_FILE_NAME = "test.txt"; - private static final String TEST_FILE_TYPE = "txt"; - private static final long TEST_FILE_SIZE = 1024L; - private static final String TEST_UPLOAD_TIME = "2024-01-01 00:00:00"; + private static final String TEST_QUERY = "test query"; @Mock - private DashScopeApi dashScopeApi; + private DocumentRetriever documentRetriever; + + @Mock + private ChatModel chatModel; @TempDir Path tempDir; - private DashScopeDocumentCloudReader reader; + private DashScopeDocumentRetrievalAdvisor advisor; + private File testFile; @BeforeEach - void setUp() { + void setUp() throws IOException { + // Initialize mocks and test objects MockitoAnnotations.openMocks(this); - reader = new DashScopeDocumentCloudReader(dashScopeApi); + + // Create test file + testFile = tempDir.resolve(TEST_FILE_NAME).toFile(); + Files.writeString(testFile.toPath(), TEST_CONTENT); + + // Set up advisor with document retriever and enable reference + advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); } @Test - void testConstructorWithNonExistentFile() { - // 测试使用不存在的文件路径创建实例 - String nonExistentPath = tempDir.resolve("non-existent.txt").toString(); - assertThatThrownBy(() -> new DashScopeDocumentCloudReader(dashScopeApi, nonExistentPath)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("Not Exist"); + void testGeneratePromptWithDocuments() { + // Prepare test data + List documents = List.of(new Document(TEST_CONTENT)); + when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); + + // Generate prompt + Map userParams = new HashMap<>(); + Map adviseContext = new HashMap<>(); + AdvisedRequest request = AdvisedRequest.builder() + .userText(TEST_QUERY) + .userParams(userParams) + .adviseContext(adviseContext) + .chatModel(chatModel) + .build(); + + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Create adviseContext with document map + Map responseAdviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + documentMap.put("[1]", documents.get(0)); + responseAdviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + + // Create question_answer_context as a Map + Map qaContext = new HashMap<>(); + qaContext.put("context", String.format("[1] 【文档名】%s\n【标题】%s\n【正文】%s\n\n", + documents.get(0).getMetadata().getOrDefault("doc_name", ""), + documents.get(0).getMetadata().getOrDefault("title", ""), + documents.get(0).getText())); + responseAdviseContext.put("question_answer_context", qaContext); + + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, responseAdviseContext)); + + // Verify response + assertThat(response).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); + assertThat(response.adviseContext()).containsKey("question_answer_context"); } @Test - void testSuccessfulDocumentParsing() throws IOException { - // 创建测试文件 - Path testFile = tempDir.resolve(TEST_FILE_NAME); - Files.write(testFile, TEST_CONTENT.getBytes()); - - // 模拟成功的文件上传和解析 - mockSuccessfulUpload(); - mockSuccessfulParsing(); - - // 执行测试 - List documents = reader.read(testFile.toString()); - - // 验证结果 - assertThat(documents).hasSize(1); - Document document = documents.get(0); - assertThat(document.getContent()).isEqualTo(TEST_CONTENT); - assertThat(document.getMetadata()).containsEntry("file_id", TEST_FILE_ID); + void testGeneratePromptWithEmptyDocuments() { + // Prepare test data + when(documentRetriever.retrieve(any(Query.class))).thenReturn(Collections.emptyList()); + + // Generate prompt + Map userParams = new HashMap<>(); + Map adviseContext = new HashMap<>(); + AdvisedRequest request = AdvisedRequest.builder() + .userText(TEST_QUERY) + .userParams(userParams) + .adviseContext(adviseContext) + .chatModel(chatModel) + .build(); + + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Create adviseContext with empty document map + Map responseAdviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + responseAdviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, responseAdviseContext)); + + // Verify response + assertThat(response).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); + assertThat((Map) response.adviseContext().get(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS)) + .isEmpty(); } @Test - void testParseFailure() throws IOException { - // 创建测试文件 - Path testFile = tempDir.resolve(TEST_FILE_NAME); - Files.write(testFile, TEST_CONTENT.getBytes()); - - // 模拟成功的文件上传但解析失败 - mockSuccessfulUpload(); - mockFailedParsing(); - - // 验证异常 - assertThatThrownBy(() -> reader.read(testFile.toString())) - .isInstanceOf(DashScopeException.class) - .hasMessageContaining("READER_PARSE_FILE_ERROR"); + void testProcessChatResponse() { + // Prepare test data + List documents = List.of(new Document(TEST_CONTENT)); + when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); + + // Create chat response with metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Process response + Map userParams = new HashMap<>(); + Map adviseContext = new HashMap<>(); + AdvisedRequest request = AdvisedRequest.builder() + .userText(TEST_QUERY) + .userParams(userParams) + .adviseContext(adviseContext) + .chatModel(chatModel) + .build(); + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, new HashMap<>())); + + // Verify response + assertThat(response).isNotNull(); + assertThat(response.response()).isNotNull(); + assertThat(response.response().getResult().getOutput().getText()).isEqualTo("Test response"); } @Test - void testPollingTimeout() throws IOException { - // 创建测试文件 - Path testFile = tempDir.resolve(TEST_FILE_NAME); - Files.write(testFile, TEST_CONTENT.getBytes()); + void testAroundCallWithEmptyDocuments() { + // Given + DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); + AdvisedRequest request = AdvisedRequest + .builder() + .userText("test message") + .chatModel(chatModel) + .build(); - // 模拟成功的文件上传但轮询超时 - mockSuccessfulUpload(); - mockPollingTimeout(); + // When + when(documentRetriever.retrieve(any(Query.class))).thenReturn(Collections.emptyList()); - // 执行测试 - List documents = reader.read(testFile.toString()); + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); - // 验证结果为空 - assertThat(documents).isNull(); - } + // Create adviseContext with retrieved documents + Map adviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); - private void mockSuccessfulUpload() { - when(dashScopeApi.uploadFile(any())).thenReturn(TEST_FILE_ID); - } + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, adviseContext)); - private void mockSuccessfulParsing() { - QueryFileResponseData successResponse = new QueryFileResponseData( - TEST_CATEGORY_ID, - TEST_FILE_ID, - TEST_FILE_NAME, - TEST_FILE_TYPE, - TEST_FILE_SIZE, - "PARSE_SUCCESS", - TEST_UPLOAD_TIME); - when(dashScopeApi.queryFile(TEST_FILE_ID)).thenReturn(successResponse); + // Then + assertThat(response).isNotNull(); + assertThat(response.response()).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); } - private void mockFailedParsing() { - QueryFileResponseData failedResponse = new QueryFileResponseData( - TEST_CATEGORY_ID, - TEST_FILE_ID, - TEST_FILE_NAME, - TEST_FILE_TYPE, - TEST_FILE_SIZE, - "PARSE_FAILED", - TEST_UPLOAD_TIME); - when(dashScopeApi.queryFile(TEST_FILE_ID)).thenReturn(failedResponse); + @Test + void testAroundCallWithNullDocuments() { + // Given + DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); + AdvisedRequest request = AdvisedRequest + .builder() + .userText("test message") + .chatModel(chatModel) + .build(); + + // When + when(documentRetriever.retrieve(any(Query.class))).thenReturn(Collections.emptyList()); + + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Create adviseContext with retrieved documents + Map adviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, adviseContext)); + + // Then + assertThat(response).isNotNull(); + assertThat(response.response()).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); + assertThat((Map) response.adviseContext().get(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS)) + .isEmpty(); } - private void mockPollingTimeout() { - QueryFileResponseData processingResponse = new QueryFileResponseData( - TEST_CATEGORY_ID, - TEST_FILE_ID, - TEST_FILE_NAME, - TEST_FILE_TYPE, - TEST_FILE_SIZE, - "PROCESSING", - TEST_UPLOAD_TIME); - when(dashScopeApi.queryFile(TEST_FILE_ID)).thenReturn(processingResponse); + @Test + void testAroundCallWithDocuments() { + // Given + DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); + AdvisedRequest request = AdvisedRequest + .builder() + .userText("test message") + .chatModel(chatModel) + .build(); + + // When + List documents = Arrays.asList( + new Document("test document 1"), + new Document("test document 2")); + when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); + + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Create adviseContext with retrieved documents + Map adviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + for (int i = 0; i < documents.size(); i++) { + documentMap.put(String.format("[%d]", i + 1), documents.get(i)); + } + adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, adviseContext)); + + // Then + assertThat(response).isNotNull(); + assertThat(response.response()).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); } -} \ No newline at end of file +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverOptionsTests.java index b8e61648..891d0901 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverOptionsTests.java @@ -15,12 +15,120 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; /** + * Test cases for DashScopeDocumentRetrieverOptions. + * Tests cover builder pattern, getters/setters, and default values. + * * @author yuluo * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ class DashScopeDocumentRetrieverOptionsTests { -} \ No newline at end of file + // Test constants + private static final String TEST_INDEX_NAME = "test-index"; + private static final int TEST_DENSE_TOP_K = 50; + private static final int TEST_SPARSE_TOP_K = 30; + private static final String TEST_REWRITE_MODEL = "test-rewrite-model"; + private static final String TEST_RERANK_MODEL = "test-rerank-model"; + private static final float TEST_RERANK_MIN_SCORE = 0.5f; + private static final int TEST_RERANK_TOP_N = 10; + + @Test + void testDefaultValues() { + // Test default constructor and default values + DashScopeDocumentRetrieverOptions options = new DashScopeDocumentRetrieverOptions(); + + // Verify default values + assertThat(options.getIndexName()).isNull(); + assertThat(options.getDenseSimilarityTopK()).isEqualTo(100); + assertThat(options.getSparseSimilarityTopK()).isEqualTo(100); + assertThat(options.isEnableRewrite()).isFalse(); + assertThat(options.getRewriteModelName()).isEqualTo("conv-rewrite-qwen-1.8b"); + assertThat(options.isEnableReranking()).isTrue(); + assertThat(options.getRerankModelName()).isEqualTo("gte-rerank-hybrid"); + assertThat(options.getRerankMinScore()).isEqualTo(0.01f); + assertThat(options.getRerankTopN()).isEqualTo(5); + } + + @Test + void testBuilderPattern() { + // Test builder pattern with all properties set + DashScopeDocumentRetrieverOptions options = DashScopeDocumentRetrieverOptions.builder() + .withIndexName(TEST_INDEX_NAME) + .withDenseSimilarityTopK(TEST_DENSE_TOP_K) + .withSparseSimilarityTopK(TEST_SPARSE_TOP_K) + .withEnableRewrite(true) + .withRewriteModelName(TEST_REWRITE_MODEL) + .withEnableReranking(false) + .withRerankModelName(TEST_RERANK_MODEL) + .withRerankMinScore(TEST_RERANK_MIN_SCORE) + .withRerankTopN(TEST_RERANK_TOP_N) + .build(); + + // Verify all properties are set correctly + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); + assertThat(options.getSparseSimilarityTopK()).isEqualTo(TEST_SPARSE_TOP_K); + assertThat(options.isEnableRewrite()).isTrue(); + assertThat(options.getRewriteModelName()).isEqualTo(TEST_REWRITE_MODEL); + assertThat(options.isEnableReranking()).isFalse(); + assertThat(options.getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); + assertThat(options.getRerankMinScore()).isEqualTo(TEST_RERANK_MIN_SCORE); + assertThat(options.getRerankTopN()).isEqualTo(TEST_RERANK_TOP_N); + } + + @Test + void testSettersAndGetters() { + // Test setters and getters + DashScopeDocumentRetrieverOptions options = new DashScopeDocumentRetrieverOptions(); + + // Set values using setters + options.setIndexName(TEST_INDEX_NAME); + options.setDenseSimilarityTopk(TEST_DENSE_TOP_K); + options.setSparseSimilarityTopk(TEST_SPARSE_TOP_K); + options.setEnableRewrite(true); + options.setRewriteModelName(TEST_REWRITE_MODEL); + options.setEnableReranking(false); + options.setRerankModelName(TEST_RERANK_MODEL); + options.setRerankMinScore(TEST_RERANK_MIN_SCORE); + options.setRerankTopN(TEST_RERANK_TOP_N); + + // Verify values using getters + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); + assertThat(options.getSparseSimilarityTopK()).isEqualTo(TEST_SPARSE_TOP_K); + assertThat(options.isEnableRewrite()).isTrue(); + assertThat(options.getRewriteModelName()).isEqualTo(TEST_REWRITE_MODEL); + assertThat(options.isEnableReranking()).isFalse(); + assertThat(options.getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); + assertThat(options.getRerankMinScore()).isEqualTo(TEST_RERANK_MIN_SCORE); + assertThat(options.getRerankTopN()).isEqualTo(TEST_RERANK_TOP_N); + } + + @Test + void testBuilderWithPartialValues() { + // Test builder with only some properties set + DashScopeDocumentRetrieverOptions options = DashScopeDocumentRetrieverOptions.builder() + .withIndexName(TEST_INDEX_NAME) + .withDenseSimilarityTopK(TEST_DENSE_TOP_K) + .build(); + + // Verify set values + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); + + // Verify unset values remain at defaults + assertThat(options.getSparseSimilarityTopK()).isEqualTo(100); + assertThat(options.isEnableRewrite()).isFalse(); + assertThat(options.getRewriteModelName()).isEqualTo("conv-rewrite-qwen-1.8b"); + assertThat(options.isEnableReranking()).isTrue(); + assertThat(options.getRerankModelName()).isEqualTo("gte-rerank-hybrid"); + assertThat(options.getRerankMinScore()).isEqualTo(0.01f); + assertThat(options.getRerankTopN()).isEqualTo(5); + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverTests.java index c1bd2c29..e47fa525 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverTests.java @@ -15,12 +15,161 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; +import com.alibaba.cloud.ai.dashscope.common.DashScopeException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.ai.document.Document; +import org.springframework.ai.rag.Query; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; /** + * Test cases for DashScopeDocumentRetriever. + * Tests cover document retrieval functionality, error handling, and edge cases. + * * @author yuluo * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ +@ExtendWith(MockitoExtension.class) class DashScopeDocumentRetrieverTests { -} \ No newline at end of file + // Test constants + private static final String TEST_INDEX_NAME = "test-index"; + private static final String TEST_PIPELINE_ID = "test-pipeline-id"; + private static final String TEST_QUERY = "test query"; + private static final String TEST_DOC_ID = "test-doc-id"; + private static final String TEST_DOC_TEXT = "test document text"; + + @Mock + private DashScopeApi dashScopeApi; + + private DashScopeDocumentRetriever retriever; + private DashScopeDocumentRetrieverOptions options; + + @BeforeEach + void setUp() { + // Initialize options with test values + options = DashScopeDocumentRetrieverOptions.builder() + .withIndexName(TEST_INDEX_NAME) + .build(); + + // Create retriever instance + retriever = new DashScopeDocumentRetriever(dashScopeApi, options); + } + + @Test + void testConstructorWithNullOptions() { + // Test constructor with null options + assertThatThrownBy(() -> new DashScopeDocumentRetriever(dashScopeApi, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("RetrieverOptions must not be null"); + } + + @Test + void testConstructorWithNullIndexName() { + // Test constructor with null index name + DashScopeDocumentRetrieverOptions optionsWithNullIndex = new DashScopeDocumentRetrieverOptions(); + assertThatThrownBy(() -> new DashScopeDocumentRetriever(dashScopeApi, optionsWithNullIndex)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("IndexName must not be null"); + } + + @Test + void testRetrieveWithNonExistentIndex() { + // Mock API response for non-existent index + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(null); + + // Test retrieval with non-existent index + assertThatThrownBy(() -> retriever.retrieve(new Query(TEST_QUERY))) + .isInstanceOf(DashScopeException.class) + .hasMessageContaining("Index:" + TEST_INDEX_NAME + " NotExist"); + } + + @Test + void testSuccessfulRetrieval() { + // Create test document with metadata + Map metadata = new HashMap<>(); + metadata.put("doc_name", "test.txt"); + metadata.put("title", "Test Document"); + Document testDoc = new Document(TEST_DOC_ID, TEST_DOC_TEXT, metadata); + List expectedDocs = List.of(testDoc); + + // Mock API responses + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); + when(dashScopeApi.retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any(DashScopeDocumentRetrieverOptions.class))) + .thenReturn(expectedDocs); + + // Test successful document retrieval + List retrievedDocs = retriever.retrieve(new Query(TEST_QUERY)); + + // Verify retrieved documents + assertThat(retrievedDocs).isNotNull().hasSize(1); + Document retrievedDoc = retrievedDocs.get(0); + assertThat(retrievedDoc.getId()).isEqualTo(TEST_DOC_ID); + assertThat(retrievedDoc.getText()).isEqualTo(TEST_DOC_TEXT); + assertThat(retrievedDoc.getMetadata()) + .containsEntry("doc_name", "test.txt") + .containsEntry("title", "Test Document"); + } + + @Test + void testEmptyRetrieval() { + // Mock API responses for empty result + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); + when(dashScopeApi.retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any(DashScopeDocumentRetrieverOptions.class))) + .thenReturn(new ArrayList<>()); + + // Test retrieval with no results + List retrievedDocs = retriever.retrieve(new Query(TEST_QUERY)); + + // Verify empty result + assertThat(retrievedDocs).isNotNull().isEmpty(); + } + + @Test + void testRetrievalWithMultipleDocuments() { + // Create multiple test documents + List expectedDocs = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Map metadata = new HashMap<>(); + metadata.put("doc_name", "test" + i + ".txt"); + metadata.put("title", "Test Document " + i); + Document doc = new Document("doc-" + i, "content " + i, metadata); + expectedDocs.add(doc); + } + + // Mock API responses + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); + when(dashScopeApi.retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any(DashScopeDocumentRetrieverOptions.class))) + .thenReturn(expectedDocs); + + // Test retrieval with multiple documents + List retrievedDocs = retriever.retrieve(new Query(TEST_QUERY)); + + // Verify retrieved documents + assertThat(retrievedDocs).isNotNull().hasSize(3); + for (int i = 0; i < retrievedDocs.size(); i++) { + Document doc = retrievedDocs.get(i); + assertThat(doc.getId()).isEqualTo("doc-" + i); + assertThat(doc.getText()).isEqualTo("content " + i); + assertThat(doc.getMetadata()) + .containsEntry("doc_name", "test" + i + ".txt") + .containsEntry("title", "Test Document " + i); + } + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerOptionsTests.java index 55d52dd3..cb80bb5d 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerOptionsTests.java @@ -15,12 +15,109 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; /** + * Test cases for DashScopeDocumentTransformerOptions. + * Tests cover default values, builder pattern, setters/getters, and partial + * value settings. + * * @author yuluo * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ class DashScopeDocumentTransformerOptionsTests { -} \ No newline at end of file + // Test constants for validation + private static final int TEST_CHUNK_SIZE = 1000; + private static final int TEST_OVERLAP_SIZE = 200; + private static final String TEST_SEPARATOR = "|,|,|。|?|!|\\n"; + private static final String TEST_FILE_TYPE = "txt"; + private static final String TEST_LANGUAGE = "en"; + + /** + * Test default values when creating a new instance. + * Verifies that all properties have their expected default values. + */ + @Test + void testDefaultValues() { + DashScopeDocumentTransformerOptions options = new DashScopeDocumentTransformerOptions(); + + // Verify default values + assertThat(options.getChunkSize()).isEqualTo(500); + assertThat(options.getOverlapSize()).isEqualTo(100); + assertThat(options.getSeparator()).isEqualTo("|,|,|。|?|!|\\n|\\\\?|\\\\!"); + assertThat(options.getFileType()).isEqualTo("idp"); + assertThat(options.getLanguage()).isEqualTo("cn"); + } + + /** + * Test the builder pattern for setting all properties. + * Verifies that all properties can be set using the builder pattern. + */ + @Test + void testBuilderPattern() { + DashScopeDocumentTransformerOptions options = DashScopeDocumentTransformerOptions.builder() + .withChunkSize(TEST_CHUNK_SIZE) + .withOverlapSize(TEST_OVERLAP_SIZE) + .withSeparator(TEST_SEPARATOR) + .withFileType(TEST_FILE_TYPE) + .withLanguage(TEST_LANGUAGE) + .build(); + + // Verify all properties are set correctly + assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); + assertThat(options.getOverlapSize()).isEqualTo(TEST_OVERLAP_SIZE); + assertThat(options.getSeparator()).isEqualTo(TEST_SEPARATOR); + assertThat(options.getFileType()).isEqualTo(TEST_FILE_TYPE); + assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); + } + + /** + * Test all setter and getter methods. + * Verifies that all properties can be set and retrieved correctly using setters + * and getters. + */ + @Test + void testSettersAndGetters() { + DashScopeDocumentTransformerOptions options = new DashScopeDocumentTransformerOptions(); + + // Set values using setters + options.setChunkSize(TEST_CHUNK_SIZE); + options.setOverlapSize(TEST_OVERLAP_SIZE); + options.setSeparator(TEST_SEPARATOR); + options.setFileType(TEST_FILE_TYPE); + options.setLanguage(TEST_LANGUAGE); + + // Verify values using getters + assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); + assertThat(options.getOverlapSize()).isEqualTo(TEST_OVERLAP_SIZE); + assertThat(options.getSeparator()).isEqualTo(TEST_SEPARATOR); + assertThat(options.getFileType()).isEqualTo(TEST_FILE_TYPE); + assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); + } + + /** + * Test builder with partial values set. + * Verifies that when only some properties are set, others retain their default + * values. + */ + @Test + void testBuilderWithPartialValues() { + DashScopeDocumentTransformerOptions options = DashScopeDocumentTransformerOptions.builder() + .withChunkSize(TEST_CHUNK_SIZE) + .withLanguage(TEST_LANGUAGE) + .build(); + + // Verify set values + assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); + assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); + + // Verify default values for unset properties + assertThat(options.getOverlapSize()).isEqualTo(100); + assertThat(options.getSeparator()).isEqualTo("|,|,|。|?|!|\\n|\\\\?|\\\\!"); + assertThat(options.getFileType()).isEqualTo("idp"); + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerTests.java index 4ea4defb..6cdbde09 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerTests.java @@ -15,12 +15,193 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; +import com.alibaba.cloud.ai.dashscope.common.DashScopeException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.ai.document.Document; +import org.springframework.http.ResponseEntity; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; /** + * Test cases for DashScopeDocumentTransformer. + * Tests cover constructor validation, document splitting, error handling, and + * successful transformations. + * * @author yuluo * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ class DashScopeDocumentTransformerTests { -} \ No newline at end of file + // Test constants + private static final String TEST_DOC_ID = "test_doc_1"; + private static final String TEST_CONTENT = "This is a test document content"; + private static final String TEST_CHUNK_CONTENT = "This is a test chunk content"; + private static final int TEST_CHUNK_ID = 1; + + @Mock + private DashScopeApi dashScopeApi; + + private DashScopeDocumentTransformer transformer; + private DashScopeDocumentTransformerOptions options; + + @BeforeEach + void setUp() { + // Initialize mocks + MockitoAnnotations.openMocks(this); + + // Create default options + options = DashScopeDocumentTransformerOptions.builder() + .withChunkSize(500) + .withOverlapSize(100) + .withSeparator("|,|,|。|?|!|\\n|\\\\?|\\\\!") + .withFileType("idp") + .withLanguage("cn") + .build(); + + // Create transformer instance + transformer = new DashScopeDocumentTransformer(dashScopeApi, options); + } + + /** + * Test constructor with null DashScopeApi. + * Should throw IllegalArgumentException. + */ + @Test + void testConstructorWithNullApi() { + assertThatThrownBy(() -> new DashScopeDocumentTransformer(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("DashScopeApi must not be null"); + } + + /** + * Test constructor with null options. + * Should throw IllegalArgumentException. + */ + @Test + void testConstructorWithNullOptions() { + assertThatThrownBy(() -> new DashScopeDocumentTransformer(dashScopeApi, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("DashScopeDocumentTransformerOptions must not be null"); + } + + /** + * Test applying transformation with null documents list. + * Should throw RuntimeException. + */ + @Test + void testApplyWithNullDocuments() { + assertThatThrownBy(() -> transformer.apply(null)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Documents must not be null"); + } + + /** + * Test applying transformation with empty documents list. + * Should throw RuntimeException. + */ + @Test + void testApplyWithEmptyDocuments() { + assertThatThrownBy(() -> transformer.apply(Collections.emptyList())) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Documents must not be null"); + } + + /** + * Test applying transformation with multiple documents. + * Should throw RuntimeException as only one document is supported. + */ + @Test + void testApplyWithMultipleDocuments() { + Map metadata = new HashMap<>(); + List documents = List.of( + new Document(TEST_DOC_ID, TEST_CONTENT, metadata), + new Document("test_doc_2", "Another test content", metadata)); + + assertThatThrownBy(() -> transformer.apply(documents)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Just support one Document"); + } + + /** + * Test successful document splitting. + * Should return list of document chunks with correct IDs and content. + */ + @Test + void testSuccessfulSplit() { + // Create test document + Map metadata = new HashMap<>(); + Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); + + // Mock API response + DashScopeApi.DocumentSplitResponse.DocumentChunk chunk = new DashScopeApi.DocumentSplitResponse.DocumentChunk( + TEST_CHUNK_ID, TEST_CHUNK_CONTENT, null, null, null, null); + DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData chunkService = new DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData( + List.of(chunk)); + DashScopeApi.DocumentSplitResponse response = new DashScopeApi.DocumentSplitResponse(chunkService); + + when(dashScopeApi.documentSplit(any(), any())) + .thenReturn(ResponseEntity.ok(response)); + + // Perform transformation + List result = transformer.apply(List.of(document)); + + // Verify results + assertThat(result).isNotNull() + .hasSize(1); + Document resultDoc = result.get(0); + assertThat(resultDoc.getId()).isEqualTo(TEST_DOC_ID + "_" + TEST_CHUNK_ID); + assertThat(resultDoc.getText()).isEqualTo(TEST_CHUNK_CONTENT); + assertThat(resultDoc.getMetadata()).isEqualTo(metadata); + } + + /** + * Test split with null API response. + * Should throw DashScopeException. + */ + @Test + void testSplitWithNullResponse() { + Map metadata = new HashMap<>(); + Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); + + when(dashScopeApi.documentSplit(any(), any())) + .thenReturn(null); + + assertThatThrownBy(() -> transformer.apply(List.of(document))) + .isInstanceOf(DashScopeException.class); + } + + /** + * Test split with empty chunks in response. + * Should throw DashScopeException. + */ + @Test + void testSplitWithEmptyChunks() { + Map metadata = new HashMap<>(); + Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); + + DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData chunkService = new DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData( + Collections.emptyList()); + DashScopeApi.DocumentSplitResponse response = new DashScopeApi.DocumentSplitResponse(chunkService); + + when(dashScopeApi.documentSplit(any(), any())) + .thenReturn(ResponseEntity.ok(response)); + + assertThatThrownBy(() -> transformer.apply(List.of(document))) + .isInstanceOf(DashScopeException.class); + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeStoreOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeStoreOptionsTests.java index 79d6f0cc..d7dc7bf8 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeStoreOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeStoreOptionsTests.java @@ -15,12 +15,148 @@ */ package com.alibaba.cloud.ai.dashscope.rag; -import static org.junit.jupiter.api.Assertions.*; +import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; /** + * Test cases for DashScopeStoreOptions. + * Tests cover constructor, getters/setters, and option configurations. + * * @author yuluo * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ class DashScopeStoreOptionsTests { -} \ No newline at end of file + // Test constants for validation + private static final String TEST_INDEX_NAME = "test-index"; + private static final String TEST_EMBEDDING_MODEL = "text-embedding-v2"; + private static final String TEST_RERANK_MODEL = "gte-rerank-hybrid"; + + /** + * Test constructor with index name. + * Verifies that the index name is correctly set in the constructor. + */ + @Test + void testConstructorWithIndexName() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + + // Verify index name is set correctly + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + + // Verify other options are null by default + assertThat(options.getTransformerOptions()).isNull(); + assertThat(options.getEmbeddingOptions()).isNull(); + assertThat(options.getRetrieverOptions()).isNull(); + } + + /** + * Test setters and getters for all options. + * Verifies that all options can be set and retrieved correctly. + */ + @Test + void testSettersAndGetters() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + + // Create and set transformer options + DashScopeDocumentTransformerOptions transformerOptions = new DashScopeDocumentTransformerOptions(); + transformerOptions.setChunkSize(1000); + options.setTransformerOptions(transformerOptions); + + // Create and set embedding options + DashScopeEmbeddingOptions embeddingOptions = DashScopeEmbeddingOptions.builder() + .withModel(TEST_EMBEDDING_MODEL) + .build(); + options.setEmbeddingOptions(embeddingOptions); + + // Create and set retriever options + DashScopeDocumentRetrieverOptions retrieverOptions = DashScopeDocumentRetrieverOptions.builder() + .withRerankModelName(TEST_RERANK_MODEL) + .build(); + options.setRetrieverOptions(retrieverOptions); + + // Verify all options are set correctly + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + assertThat(options.getTransformerOptions()).isEqualTo(transformerOptions); + assertThat(options.getEmbeddingOptions()).isEqualTo(embeddingOptions); + assertThat(options.getRetrieverOptions()).isEqualTo(retrieverOptions); + } + + /** + * Test setting index name after construction. + * Verifies that the index name can be modified after object creation. + */ + @Test + void testSetIndexName() { + String newIndexName = "new-test-index"; + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + + options.setIndexName(newIndexName); + + assertThat(options.getIndexName()).isEqualTo(newIndexName); + } + + /** + * Test setting transformer options with default values. + * Verifies that transformer options with default values are handled correctly. + */ + @Test + void testTransformerOptionsWithDefaults() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + DashScopeDocumentTransformerOptions transformerOptions = new DashScopeDocumentTransformerOptions(); + + options.setTransformerOptions(transformerOptions); + + // Verify default values + assertThat(options.getTransformerOptions().getChunkSize()).isEqualTo(500); + assertThat(options.getTransformerOptions().getOverlapSize()).isEqualTo(100); + assertThat(options.getTransformerOptions().getLanguage()).isEqualTo("cn"); + } + + /** + * Test setting embedding options with custom configuration. + * Verifies that embedding options can be customized and retrieved correctly. + */ + @Test + void testEmbeddingOptionsWithCustomConfig() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + DashScopeEmbeddingOptions embeddingOptions = DashScopeEmbeddingOptions.builder() + .withModel(TEST_EMBEDDING_MODEL) + .withTextType("document") + .withDimensions(1536) + .build(); + + options.setEmbeddingOptions(embeddingOptions); + + // Verify custom values + assertThat(options.getEmbeddingOptions().getModel()).isEqualTo(TEST_EMBEDDING_MODEL); + assertThat(options.getEmbeddingOptions().getTextType()).isEqualTo("document"); + assertThat(options.getEmbeddingOptions().getDimensions()).isEqualTo(1536); + } + + /** + * Test setting retriever options with custom configuration. + * Verifies that retriever options can be customized and retrieved correctly. + */ + @Test + void testRetrieverOptionsWithCustomConfig() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + DashScopeDocumentRetrieverOptions retrieverOptions = DashScopeDocumentRetrieverOptions.builder() + .withDenseSimilarityTopK(50) + .withSparseSimilarityTopK(30) + .withEnableReranking(true) + .withRerankModelName(TEST_RERANK_MODEL) + .build(); + + options.setRetrieverOptions(retrieverOptions); + + // Verify custom values + assertThat(options.getRetrieverOptions().getDenseSimilarityTopK()).isEqualTo(50); + assertThat(options.getRetrieverOptions().getSparseSimilarityTopK()).isEqualTo(30); + assertThat(options.getRetrieverOptions().isEnableReranking()).isTrue(); + assertThat(options.getRetrieverOptions().getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/OpenSearchConfigTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/OpenSearchConfigTests.java deleted file mode 100644 index 616921af..00000000 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/OpenSearchConfigTests.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.cloud.ai.dashscope.rag; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * @author yuluo - * @author yuluo - */ -class OpenSearchConfigTests { - -} \ No newline at end of file diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/OpenSearchVectorTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/OpenSearchVectorTests.java deleted file mode 100644 index 30ea69eb..00000000 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/OpenSearchVectorTests.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.cloud.ai.dashscope.rag; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * @author yuluo - * @author yuluo - */ -class OpenSearchVectorTests { - -} \ No newline at end of file From f880b857bacfef557b687bf9eb83ed9c7122b733 Mon Sep 17 00:00:00 2001 From: Xia Dong Date: Wed, 26 Feb 2025 17:51:38 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=AE=8C=E6=88=90rerank=E7=9A=84=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rerank/DashScopeRerankModelTests.java | 199 +++++++++++++++++- .../rerank/DashScopeRerankOptionsTests.java | 83 +++++++- .../ai/document/DocumentWithScoreTests.java | 4 +- .../ai/document/JsonDocumentParserTests.java | 4 +- .../ai/document/TextDocumentParserTests.java | 4 +- 5 files changed, 286 insertions(+), 8 deletions(-) diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankModelTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankModelTests.java index aad3a6e1..2a6fa25f 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankModelTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankModelTests.java @@ -15,12 +15,205 @@ */ package com.alibaba.cloud.ai.dashscope.rerank; -import static org.junit.jupiter.api.Assertions.*; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.RerankResponse; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.RerankResponseOutput; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.RerankResponseOutputResult; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.TokenUsage; +import com.alibaba.cloud.ai.document.DocumentWithScore; +import com.alibaba.cloud.ai.model.RerankRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.ai.document.Document; +import org.springframework.http.ResponseEntity; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; /** - * @author yuluo + * Test cases for DashScopeRerankModel. + * Tests cover constructor validation, reranking functionality, error handling, + * and response processing. + * + * @author yuanci.ytb * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ +@ExtendWith(MockitoExtension.class) class DashScopeRerankModelTests { -} \ No newline at end of file + // Test constants + private static final String TEST_MODEL = "gte-rerank"; + private static final String TEST_QUERY = "test query"; + private static final String TEST_DOC_TEXT = "test document text"; + private static final Double TEST_SCORE = 0.85; + + @Mock + private DashScopeApi dashScopeApi; + + private DashScopeRerankModel rerankModel; + private DashScopeRerankOptions defaultOptions; + + @BeforeEach + void setUp() { + // Initialize default options + defaultOptions = DashScopeRerankOptions.builder() + .withModel(TEST_MODEL) + .withTopN(3) + .withReturnDocuments(false) + .build(); + + // Initialize rerank model + rerankModel = new DashScopeRerankModel(dashScopeApi, defaultOptions); + } + + /** + * Test constructor with null DashScopeApi. + * Verifies that constructor throws IllegalArgumentException when DashScopeApi + * is null. + */ + @Test + void testConstructorWithNullApi() { + assertThatThrownBy(() -> new DashScopeRerankModel(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("DashScopeApi must not be null"); + } + + /** + * Test constructor with null options. + * Verifies that constructor throws IllegalArgumentException when options is + * null. + */ + @Test + void testConstructorWithNullOptions() { + assertThatThrownBy(() -> new DashScopeRerankModel(dashScopeApi, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Options must not be null"); + } + + /** + * Test reranking with null query. + * Verifies that reranking throws IllegalArgumentException when query is null. + */ + @Test + void testRerankWithNullQuery() { + List documents = Collections.singletonList(new Document(TEST_DOC_TEXT)); + RerankRequest request = new RerankRequest(null, documents); + + assertThatThrownBy(() -> rerankModel.call(request)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("query must not be null"); + } + + /** + * Test reranking with null documents. + * Verifies that reranking throws IllegalArgumentException when documents list + * is null. + */ + @Test + void testRerankWithNullDocuments() { + RerankRequest request = new RerankRequest(TEST_QUERY, null); + + assertThatThrownBy(() -> rerankModel.call(request)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("documents must not be null"); + } + + /** + * Test successful reranking. + * Verifies that reranking returns correct scores and documents. + */ + @Test + void testSuccessfulRerank() { + // Prepare test data + Document doc1 = new Document(TEST_DOC_TEXT + "1"); + Document doc2 = new Document(TEST_DOC_TEXT + "2"); + List documents = Arrays.asList(doc1, doc2); + + // Mock API response + RerankResponseOutputResult result1 = new RerankResponseOutputResult(0, 0.9, new HashMap<>()); + RerankResponseOutputResult result2 = new RerankResponseOutputResult(1, 0.7, new HashMap<>()); + RerankResponseOutput output = new RerankResponseOutput(Arrays.asList(result1, result2)); + TokenUsage usage = new TokenUsage(10, 20, 30); + RerankResponse apiResponse = new RerankResponse(output, usage, "test-request-id"); + + when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(apiResponse)); + + // Execute rerank + RerankRequest request = new RerankRequest(TEST_QUERY, documents); + com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); + + // Verify results + List results = response.getResults(); + assertThat(results).hasSize(2); + assertThat(results.get(0).getScore()).isEqualTo(0.9); + assertThat(results.get(1).getScore()).isEqualTo(0.7); + assertThat(results.get(0).getOutput()).isEqualTo(doc1); + assertThat(results.get(1).getOutput()).isEqualTo(doc2); + } + + /** + * Test reranking with empty response. + * Verifies that reranking handles empty API response correctly. + */ + @Test + void testEmptyResponse() { + // Prepare test data + Document doc = new Document(TEST_DOC_TEXT); + List documents = Collections.singletonList(doc); + + // Mock empty API response + when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(null)); + + // Execute rerank + RerankRequest request = new RerankRequest(TEST_QUERY, documents); + com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); + + // Verify empty results + assertThat(response.getResults()).isEmpty(); + } + + /** + * Test reranking with custom options. + * Verifies that reranking uses custom options correctly. + */ + @Test + void testCustomOptions() { + // Prepare test data + Document doc = new Document(TEST_DOC_TEXT); + List documents = Collections.singletonList(doc); + + // Create custom options + DashScopeRerankOptions customOptions = DashScopeRerankOptions.builder() + .withModel("custom-model") + .withTopN(5) + .withReturnDocuments(true) + .build(); + + // Mock API response + RerankResponseOutputResult result = new RerankResponseOutputResult(0, TEST_SCORE, new HashMap<>()); + RerankResponseOutput output = new RerankResponseOutput(Collections.singletonList(result)); + RerankResponse apiResponse = new RerankResponse(output, new TokenUsage(10, 20, 30), "test-request-id"); + + when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(apiResponse)); + + // Execute rerank with custom options + RerankRequest request = new RerankRequest(TEST_QUERY, documents, customOptions); + com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); + + // Verify results + assertThat(response.getResults()).hasSize(1); + assertThat(response.getResults().get(0).getScore()).isEqualTo(TEST_SCORE); + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankOptionsTests.java index 6242036f..af3899f9 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankOptionsTests.java @@ -15,12 +15,91 @@ */ package com.alibaba.cloud.ai.dashscope.rerank; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; /** + * Test cases for DashScopeRerankOptions. + * Tests cover default values, builder pattern, and property modifications. + * * @author yuluo * @author yuluo + * @author brianxiadong + * @since 1.0.0-M5.1 */ class DashScopeRerankOptionsTests { -} \ No newline at end of file + // Test constants + private static final String TEST_MODEL = "test-rerank-model"; + private static final Integer TEST_TOP_N = 5; + private static final Boolean TEST_RETURN_DOCUMENTS = true; + + /** + * Test default values of DashScopeRerankOptions. + * Verifies that a newly created instance has the expected default values: + * - model = "gte-rerank" + * - topN = 3 + * - returnDocuments = false + */ + @Test + void testDefaultValues() { + DashScopeRerankOptions options = DashScopeRerankOptions.builder().build(); + + assertThat(options.getModel()).isEqualTo("gte-rerank"); + assertThat(options.getTopN()).isEqualTo(3); + assertThat(options.getReturnDocuments()).isFalse(); + } + + /** + * Test builder pattern with all properties set. + * Verifies that all properties can be set using the builder pattern + * and are correctly assigned to the created instance. + */ + @Test + void testBuilderPattern() { + DashScopeRerankOptions options = DashScopeRerankOptions.builder() + .withModel(TEST_MODEL) + .withTopN(TEST_TOP_N) + .withReturnDocuments(TEST_RETURN_DOCUMENTS) + .build(); + + assertThat(options.getModel()).isEqualTo(TEST_MODEL); + assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); + assertThat(options.getReturnDocuments()).isEqualTo(TEST_RETURN_DOCUMENTS); + } + + /** + * Test setters and getters. + * Verifies that all properties can be modified after instance creation + * using setter methods and retrieved using getter methods. + */ + @Test + void testSettersAndGetters() { + DashScopeRerankOptions options = DashScopeRerankOptions.builder().build(); + + options.setModel(TEST_MODEL); + options.setTopN(TEST_TOP_N); + options.setReturnDocuments(TEST_RETURN_DOCUMENTS); + + assertThat(options.getModel()).isEqualTo(TEST_MODEL); + assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); + assertThat(options.getReturnDocuments()).isEqualTo(TEST_RETURN_DOCUMENTS); + } + + /** + * Test builder with partial values set. + * Verifies that when only some properties are set using the builder, + * the unset properties retain their default values. + */ + @Test + void testBuilderWithPartialValues() { + DashScopeRerankOptions options = DashScopeRerankOptions.builder() + .withModel(TEST_MODEL) + .withTopN(TEST_TOP_N) + .build(); + + assertThat(options.getModel()).isEqualTo(TEST_MODEL); + assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); + assertThat(options.getReturnDocuments()).isFalse(); // Default value + } +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/DocumentWithScoreTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/DocumentWithScoreTests.java index bcd19c3d..5dfb0bf6 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/DocumentWithScoreTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/DocumentWithScoreTests.java @@ -27,6 +27,8 @@ /** * Test cases for DocumentWithScore * + * @author yuluo + * @author yuluo * @author brianxiadong * @since 1.0.0-M5.1 */ @@ -145,4 +147,4 @@ private Map createMetadata() { return metadata; } -} \ No newline at end of file +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/JsonDocumentParserTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/JsonDocumentParserTests.java index ab7ffbb7..b3d919ed 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/JsonDocumentParserTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/JsonDocumentParserTests.java @@ -30,6 +30,8 @@ /** * Test cases for JsonDocumentParser * + * @author yuluo + * @author yuluo * @author brianxiadong * @since 1.0.0-M5.1 */ @@ -132,4 +134,4 @@ private InputStream toInputStream(String content) { return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); } -} \ No newline at end of file +} diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/TextDocumentParserTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/TextDocumentParserTests.java index 35e32fb2..09abbc03 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/TextDocumentParserTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/document/TextDocumentParserTests.java @@ -30,6 +30,8 @@ /** * Test cases for TextDocumentParser * + * @author yuluo + * @author yuluo * @author brianxiadong * @since 1.0.0-M5.1 */ @@ -91,4 +93,4 @@ private InputStream toInputStream(String content) { return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); } -} \ No newline at end of file +} From 21e366283a8a3934076266bb860059a190973448 Mon Sep 17 00:00:00 2001 From: Xia Dong Date: Wed, 26 Feb 2025 17:54:07 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E5=AE=8C=E6=88=90rerank=E7=9A=84=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DashScopeWebSocketClientTests.java | 328 ++++++------- .../rag/DashScopeCloudStoreTests.java | 180 ++++---- ...hScopeDocumentCloudReaderOptionsTests.java | 36 +- .../DashScopeDocumentCloudReaderTests.java | 226 +++++---- ...ashScopeDocumentRetrievalAdvisorTests.java | 430 +++++++++--------- ...ashScopeDocumentRetrieverOptionsTests.java | 215 ++++----- .../rag/DashScopeDocumentRetrieverTests.java | 192 ++++---- ...hScopeDocumentTransformerOptionsTests.java | 188 ++++---- .../DashScopeDocumentTransformerTests.java | 309 ++++++------- .../rag/DashScopeStoreOptionsTests.java | 263 +++++------ .../rerank/DashScopeRerankModelTests.java | 330 +++++++------- .../rerank/DashScopeRerankOptionsTests.java | 130 +++--- 12 files changed, 1402 insertions(+), 1425 deletions(-) diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java index 5a96d791..34384539 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/protocol/DashScopeWebSocketClientTests.java @@ -37,8 +37,8 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test cases for DashScopeWebSocketClient. Tests cover WebSocket connection, - * message handling, and event processing. + * Test cases for DashScopeWebSocketClient. Tests cover WebSocket connection, message + * handling, and event processing. * * @author yuluo * @author yuluo @@ -47,166 +47,166 @@ */ class DashScopeWebSocketClientTests { - private static final String TEST_API_KEY = "test-api-key"; - private static final String TEST_WORKSPACE_ID = "test-workspace"; - private static final String TEST_MESSAGE = "Hello, WebSocket!"; - - private DashScopeWebSocketClient client; - private WebSocket mockWebSocket; - private Response mockResponse; - - @BeforeEach - void setUp() { - // Initialize mocks - mockWebSocket = mock(WebSocket.class); - mockResponse = mock(Response.class); - - // Set up basic mock behavior - when(mockWebSocket.send(any(String.class))).thenReturn(true); - when(mockWebSocket.send(any(ByteString.class))).thenReturn(true); - - // Configure client options - DashScopeWebSocketClientOptions options = DashScopeWebSocketClientOptions.builder() - .withApiKey(TEST_API_KEY) - .withWorkSpaceId(TEST_WORKSPACE_ID) - .build(); - - // Initialize client - client = new DashScopeWebSocketClient(options); - - // Set webSocketClient using reflection - try { - Field webSocketClientField = DashScopeWebSocketClient.class.getDeclaredField("webSocketClient"); - webSocketClientField.setAccessible(true); - webSocketClientField.set(client, mockWebSocket); - - // Set isOpen to true - Field isOpenField = DashScopeWebSocketClient.class.getDeclaredField("isOpen"); - isOpenField.setAccessible(true); - isOpenField.set(client, new AtomicBoolean(true)); - } catch (Exception e) { - throw new RuntimeException("Failed to set fields via reflection", e); - } - } - - @Test - void testWebSocketEvents() { - // Test sending text message - client.sendText(TEST_MESSAGE); - verify(mockWebSocket).send(TEST_MESSAGE); - - // Test receiving task started event - client.onMessage(mockWebSocket, createTaskStartedMessage()); - - // Test receiving result generated event - client.onMessage(mockWebSocket, createResultGeneratedMessage()); - - // Test receiving task finished event - client.onMessage(mockWebSocket, createTaskFinishedMessage()); - } - - @Test - void testStreamBinaryOut() { - // Test binary streaming - String testText = "Test binary streaming"; - Flux result = client.streamBinaryOut(testText); - - StepVerifier.create(result) - .expectSubscription() - .then(() -> { - // Simulate binary message - ByteString testBinary = ByteString.of(ByteBuffer.wrap("test data".getBytes())); - client.onMessage(mockWebSocket, testBinary); - }) - .expectNextMatches(buffer -> buffer.hasRemaining()) - .then(() -> client.onMessage(mockWebSocket, createTaskFinishedMessage())) - .verifyComplete(); - } - - @Test - void testStreamTextOut() { - // Test text streaming - ByteBuffer testBuffer = ByteBuffer.wrap("Test text streaming".getBytes()); - Flux result = client.streamTextOut(Flux.just(testBuffer)); - - StepVerifier.create(result) - .expectSubscription() - .then(() -> client.onMessage(mockWebSocket, createResultGeneratedMessage())) - .expectNextMatches(text -> text.contains("result")) - .then(() -> client.onMessage(mockWebSocket, createTaskFinishedMessage())) - .verifyComplete(); - } - - @Test - void testErrorHandling() { - // Test error handling - Exception testException = new Exception("Test error"); - client.onFailure(mockWebSocket, testException, mockResponse); - - // Verify error is propagated to emitters - StepVerifier.create(client.streamBinaryOut(TEST_MESSAGE)) - .expectError() - .verify(); - } - - @Test - void testTaskFailedEvent() { - // Test task failed event - client.onMessage(mockWebSocket, createTaskFailedMessage()); - - // Verify error is propagated to emitters - StepVerifier.create(client.streamTextOut(Flux.just(ByteBuffer.wrap("test".getBytes())))) - .expectError() - .verify(); - } - - private String createTaskStartedMessage() { - return """ - { - "header": { - "task_id": "test-task-id", - "event": "task-started" - }, - "payload": {} - }"""; - } - - private String createResultGeneratedMessage() { - return """ - { - "header": { - "task_id": "test-task-id", - "event": "result-generated" - }, - "payload": { - "output": { - "text": "test result" - } - } - }"""; - } - - private String createTaskFinishedMessage() { - return """ - { - "header": { - "task_id": "test-task-id", - "event": "task-finished" - }, - "payload": {} - }"""; - } - - private String createTaskFailedMessage() { - return """ - { - "header": { - "task_id": "test-task-id", - "event": "task-failed", - "error_code": "500", - "error_message": "Test error" - }, - "payload": {} - }"""; - } + private static final String TEST_API_KEY = "test-api-key"; + + private static final String TEST_WORKSPACE_ID = "test-workspace"; + + private static final String TEST_MESSAGE = "Hello, WebSocket!"; + + private DashScopeWebSocketClient client; + + private WebSocket mockWebSocket; + + private Response mockResponse; + + @BeforeEach + void setUp() { + // Initialize mocks + mockWebSocket = mock(WebSocket.class); + mockResponse = mock(Response.class); + + // Set up basic mock behavior + when(mockWebSocket.send(any(String.class))).thenReturn(true); + when(mockWebSocket.send(any(ByteString.class))).thenReturn(true); + + // Configure client options + DashScopeWebSocketClientOptions options = DashScopeWebSocketClientOptions.builder() + .withApiKey(TEST_API_KEY) + .withWorkSpaceId(TEST_WORKSPACE_ID) + .build(); + + // Initialize client + client = new DashScopeWebSocketClient(options); + + // Set webSocketClient using reflection + try { + Field webSocketClientField = DashScopeWebSocketClient.class.getDeclaredField("webSocketClient"); + webSocketClientField.setAccessible(true); + webSocketClientField.set(client, mockWebSocket); + + // Set isOpen to true + Field isOpenField = DashScopeWebSocketClient.class.getDeclaredField("isOpen"); + isOpenField.setAccessible(true); + isOpenField.set(client, new AtomicBoolean(true)); + } + catch (Exception e) { + throw new RuntimeException("Failed to set fields via reflection", e); + } + } + + @Test + void testWebSocketEvents() { + // Test sending text message + client.sendText(TEST_MESSAGE); + verify(mockWebSocket).send(TEST_MESSAGE); + + // Test receiving task started event + client.onMessage(mockWebSocket, createTaskStartedMessage()); + + // Test receiving result generated event + client.onMessage(mockWebSocket, createResultGeneratedMessage()); + + // Test receiving task finished event + client.onMessage(mockWebSocket, createTaskFinishedMessage()); + } + + @Test + void testStreamBinaryOut() { + // Test binary streaming + String testText = "Test binary streaming"; + Flux result = client.streamBinaryOut(testText); + + StepVerifier.create(result).expectSubscription().then(() -> { + // Simulate binary message + ByteString testBinary = ByteString.of(ByteBuffer.wrap("test data".getBytes())); + client.onMessage(mockWebSocket, testBinary); + }) + .expectNextMatches(buffer -> buffer.hasRemaining()) + .then(() -> client.onMessage(mockWebSocket, createTaskFinishedMessage())) + .verifyComplete(); + } + + @Test + void testStreamTextOut() { + // Test text streaming + ByteBuffer testBuffer = ByteBuffer.wrap("Test text streaming".getBytes()); + Flux result = client.streamTextOut(Flux.just(testBuffer)); + + StepVerifier.create(result) + .expectSubscription() + .then(() -> client.onMessage(mockWebSocket, createResultGeneratedMessage())) + .expectNextMatches(text -> text.contains("result")) + .then(() -> client.onMessage(mockWebSocket, createTaskFinishedMessage())) + .verifyComplete(); + } + + @Test + void testErrorHandling() { + // Test error handling + Exception testException = new Exception("Test error"); + client.onFailure(mockWebSocket, testException, mockResponse); + + // Verify error is propagated to emitters + StepVerifier.create(client.streamBinaryOut(TEST_MESSAGE)).expectError().verify(); + } + + @Test + void testTaskFailedEvent() { + // Test task failed event + client.onMessage(mockWebSocket, createTaskFailedMessage()); + + // Verify error is propagated to emitters + StepVerifier.create(client.streamTextOut(Flux.just(ByteBuffer.wrap("test".getBytes())))).expectError().verify(); + } + + private String createTaskStartedMessage() { + return """ + { + "header": { + "task_id": "test-task-id", + "event": "task-started" + }, + "payload": {} + }"""; + } + + private String createResultGeneratedMessage() { + return """ + { + "header": { + "task_id": "test-task-id", + "event": "result-generated" + }, + "payload": { + "output": { + "text": "test result" + } + } + }"""; + } + + private String createTaskFinishedMessage() { + return """ + { + "header": { + "task_id": "test-task-id", + "event": "task-finished" + }, + "payload": {} + }"""; + } + + private String createTaskFailedMessage() { + return """ + { + "header": { + "task_id": "test-task-id", + "event": "task-failed", + "error_code": "500", + "error_message": "Test error" + }, + "payload": {} + }"""; + } + } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java index 1f3bec74..7d645bda 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeCloudStoreTests.java @@ -47,59 +47,61 @@ */ class DashScopeCloudStoreTests { - @Mock - private DashScopeApi dashScopeApi; + @Mock + private DashScopeApi dashScopeApi; - private DashScopeCloudStore cloudStore; - private DashScopeStoreOptions options; + private DashScopeCloudStore cloudStore; - private static final String TEST_INDEX_NAME = "test-index"; - private static final String TEST_PIPELINE_ID = "test-pipeline-id"; - private static final String TEST_QUERY = "test query"; + private DashScopeStoreOptions options; - @BeforeEach - void setUp() { - // Initialize Mockito annotations - MockitoAnnotations.openMocks(this); + private static final String TEST_INDEX_NAME = "test-index"; - // Set up basic configuration - options = new DashScopeStoreOptions(TEST_INDEX_NAME); - cloudStore = new DashScopeCloudStore(dashScopeApi, options); + private static final String TEST_PIPELINE_ID = "test-pipeline-id"; - // Set up basic mock behavior - when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); - } + private static final String TEST_QUERY = "test query"; - @Test - void testAddDocumentsWithNullList() { - // Test adding null document list - assertThrows(DashScopeException.class, () -> cloudStore.add(null)); - } + @BeforeEach + void setUp() { + // Initialize Mockito annotations + MockitoAnnotations.openMocks(this); - @Test - void testAddDocumentsWithEmptyList() { - // Test adding empty document list - assertThrows(DashScopeException.class, () -> cloudStore.add(new ArrayList<>())); - } + // Set up basic configuration + options = new DashScopeStoreOptions(TEST_INDEX_NAME); + cloudStore = new DashScopeCloudStore(dashScopeApi, options); - @Test - void testAddDocumentsSuccessfully() { - // Create test documents - Map metadata = new HashMap<>(); - metadata.put("key", "value"); + // Set up basic mock behavior + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); + } - List documents = Arrays.asList( - new Document("id1", "content1", metadata), - new Document("id2", "content2", metadata)); + @Test + void testAddDocumentsWithNullList() { + // Test adding null document list + assertThrows(DashScopeException.class, () -> cloudStore.add(null)); + } - // Execute add operation - cloudStore.add(documents); + @Test + void testAddDocumentsWithEmptyList() { + // Test adding empty document list + assertThrows(DashScopeException.class, () -> cloudStore.add(new ArrayList<>())); + } - // Verify API call - verify(dashScopeApi).upsertPipeline(eq(documents), eq(options)); - } + @Test + void testAddDocumentsSuccessfully() { + // Create test documents + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + List documents = Arrays.asList(new Document("id1", "content1", metadata), + new Document("id2", "content2", metadata)); + + // Execute add operation + cloudStore.add(documents); + + // Verify API call + verify(dashScopeApi).upsertPipeline(eq(documents), eq(options)); + } - @Test + @Test void testDeleteDocumentsWithNonExistentIndex() { // Mock non-existent index scenario when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(null); @@ -109,19 +111,19 @@ void testDeleteDocumentsWithNonExistentIndex() { assertThrows(DashScopeException.class, () -> cloudStore.delete(ids)); } - @Test - void testDeleteDocumentsSuccessfully() { - // Prepare test data - List ids = Arrays.asList("id1", "id2"); + @Test + void testDeleteDocumentsSuccessfully() { + // Prepare test data + List ids = Arrays.asList("id1", "id2"); - // Execute delete operation - cloudStore.delete(ids); + // Execute delete operation + cloudStore.delete(ids); - // Verify API call - verify(dashScopeApi).deletePipelineDocument(TEST_PIPELINE_ID, ids); - } + // Verify API call + verify(dashScopeApi).deletePipelineDocument(TEST_PIPELINE_ID, ids); + } - @Test + @Test void testSimilaritySearchWithNonExistentIndex() { // Mock non-existent index scenario when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(null); @@ -130,53 +132,49 @@ void testSimilaritySearchWithNonExistentIndex() { assertThrows(DashScopeException.class, () -> cloudStore.similaritySearch(TEST_QUERY)); } - @Test - void testSimilaritySearchSuccessfully() { - // Prepare test data - Map metadata = new HashMap<>(); - metadata.put("key", "value"); + @Test + void testSimilaritySearchSuccessfully() { + // Prepare test data + Map metadata = new HashMap<>(); + metadata.put("key", "value"); - List expectedResults = Arrays.asList( - new Document("id1", "result1", metadata), - new Document("id2", "result2", metadata)); - when(dashScopeApi.retriever(anyString(), anyString(), any())).thenReturn(expectedResults); + List expectedResults = Arrays.asList(new Document("id1", "result1", metadata), + new Document("id2", "result2", metadata)); + when(dashScopeApi.retriever(anyString(), anyString(), any())).thenReturn(expectedResults); - // Execute search - List results = cloudStore.similaritySearch(TEST_QUERY); + // Execute search + List results = cloudStore.similaritySearch(TEST_QUERY); - // Verify results - assertThat(results).isEqualTo(expectedResults); - verify(dashScopeApi).retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any()); - } + // Verify results + assertThat(results).isEqualTo(expectedResults); + verify(dashScopeApi).retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any()); + } - @Test - void testSimilaritySearchWithSearchRequest() { - // Prepare test data - SearchRequest request = SearchRequest.builder() - .query(TEST_QUERY) - .topK(5) - .build(); + @Test + void testSimilaritySearchWithSearchRequest() { + // Prepare test data + SearchRequest request = SearchRequest.builder().query(TEST_QUERY).topK(5).build(); - Map metadata = new HashMap<>(); - metadata.put("key", "value"); + Map metadata = new HashMap<>(); + metadata.put("key", "value"); - List expectedResults = Arrays.asList( - new Document("id1", "result1", metadata), - new Document("id2", "result2", metadata)); - when(dashScopeApi.retriever(anyString(), anyString(), any())).thenReturn(expectedResults); + List expectedResults = Arrays.asList(new Document("id1", "result1", metadata), + new Document("id2", "result2", metadata)); + when(dashScopeApi.retriever(anyString(), anyString(), any())).thenReturn(expectedResults); - // Execute search - List results = cloudStore.similaritySearch(request); + // Execute search + List results = cloudStore.similaritySearch(request); - // Verify results - assertThat(results).isEqualTo(expectedResults); - verify(dashScopeApi).retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any()); - } + // Verify results + assertThat(results).isEqualTo(expectedResults); + verify(dashScopeApi).retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any()); + } + + @Test + void testGetName() { + // Test getting name + String name = cloudStore.getName(); + assertThat(name).isEqualTo("DashScopeCloudStore"); + } - @Test - void testGetName() { - // Test getting name - String name = cloudStore.getName(); - assertThat(name).isEqualTo("DashScopeCloudStore"); - } } \ No newline at end of file diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java index a4a5dd23..4011d2ff 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderOptionsTests.java @@ -19,9 +19,8 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test cases for DashScopeDocumentCloudReaderOptions. Tests cover default - * constructor - * and parameterized constructor behavior. + * Test cases for DashScopeDocumentCloudReaderOptions. Tests cover default constructor and + * parameterized constructor behavior. * * @author yuluo * @author yuluo @@ -30,22 +29,23 @@ */ class DashScopeDocumentCloudReaderOptionsTests { - @Test - void testDefaultConstructor() { - // Test default constructor - DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(); + @Test + void testDefaultConstructor() { + // Test default constructor + DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(); - // Verify default value is "default" - assertThat(options.getCategoryId()).isEqualTo("default"); - } + // Verify default value is "default" + assertThat(options.getCategoryId()).isEqualTo("default"); + } - @Test - void testParameterizedConstructor() { - // Test parameterized constructor - String customCategoryId = "custom-category"; - DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(customCategoryId); + @Test + void testParameterizedConstructor() { + // Test parameterized constructor + String customCategoryId = "custom-category"; + DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(customCategoryId); + + // Verify custom value is set correctly + assertThat(options.getCategoryId()).isEqualTo(customCategoryId); + } - // Verify custom value is set correctly - assertThat(options.getCategoryId()).isEqualTo(customCategoryId); - } } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java index 0734ff0f..417b5620 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentCloudReaderTests.java @@ -40,9 +40,8 @@ import static org.mockito.Mockito.when; /** - * Test cases for DashScopeDocumentCloudReader. Tests cover file handling, - * document parsing, - * and error scenarios. + * Test cases for DashScopeDocumentCloudReader. Tests cover file handling, document + * parsing, and error scenarios. * * @author yuluo * @author yuluo @@ -51,120 +50,109 @@ */ class DashScopeDocumentCloudReaderTests { - private static final String TEST_CATEGORY_ID = "test-category"; - private static final String TEST_FILE_ID = "test-file-id"; - private static final String TEST_CONTENT = "Test content"; - private static final String TEST_FILE_NAME = "test.txt"; - private static final String TEST_FILE_TYPE = "txt"; - private static final long TEST_FILE_SIZE = 1024L; - private static final String TEST_UPLOAD_TIME = "2024-01-01 00:00:00"; - - @Mock - private DashScopeApi dashScopeApi; - - @TempDir - Path tempDir; - - private DashScopeDocumentCloudReader reader; - private File testFile; - - @BeforeEach - void setUp() throws IOException { - // Initialize mocks and test objects - MockitoAnnotations.openMocks(this); - - // Create test file - testFile = tempDir.resolve(TEST_FILE_NAME).toFile(); - Files.writeString(testFile.toPath(), TEST_CONTENT); - - // Set up reader with options - DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(TEST_CATEGORY_ID); - reader = new DashScopeDocumentCloudReader(testFile.getAbsolutePath(), dashScopeApi, options); - - // Mock successful file upload - mockSuccessfulUpload(); - } - - @Test - void testConstructorWithNonExistentFile() { - // Test constructor with non-existent file - String nonExistentPath = tempDir.resolve("nonexistent.txt").toString(); - assertThatThrownBy(() -> new DashScopeDocumentCloudReader(nonExistentPath, dashScopeApi, - new DashScopeDocumentCloudReaderOptions())) - .isInstanceOf(RuntimeException.class); - } - - @Test - void testSuccessfulDocumentParsing() throws IOException { - // Test successful document parsing - mockSuccessfulParsing(); - - List documents = reader.get(); - - assertThat(documents).hasSize(1); - assertThat(documents.get(0).getText()).isEqualTo(TEST_CONTENT); - } - - @Test - void testParseFailure() throws IOException { - // Test parse failure - mockFailedParsing(); - - assertThatThrownBy(() -> reader.get()) - .isInstanceOf(RuntimeException.class); - } - - private void mockSuccessfulUpload() { - DashScopeApi.UploadRequest request = new DashScopeApi.UploadRequest(TEST_CATEGORY_ID, TEST_FILE_NAME, - TEST_FILE_SIZE, "md5"); - when(dashScopeApi.upload(any(File.class), any(DashScopeApi.UploadRequest.class))).thenReturn(TEST_FILE_ID); - } - - private void mockSuccessfulParsing() { - DashScopeApi.QueryFileResponseData successResponse = new DashScopeApi.QueryFileResponseData( - TEST_CATEGORY_ID, - TEST_FILE_ID, - TEST_FILE_NAME, - TEST_FILE_TYPE, - TEST_FILE_SIZE, - "PARSE_SUCCESS", - TEST_UPLOAD_TIME); - DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( - "SUCCESS", "OK", successResponse); - when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) - .thenReturn(ResponseEntity.ok(response)); - when(dashScopeApi.getFileParseResult(eq(TEST_CATEGORY_ID), - any(DashScopeApi.UploadRequest.QueryFileRequest.class))) - .thenReturn(TEST_CONTENT); - } - - private void mockFailedParsing() { - DashScopeApi.QueryFileResponseData failedResponse = new DashScopeApi.QueryFileResponseData( - TEST_CATEGORY_ID, - TEST_FILE_ID, - TEST_FILE_NAME, - TEST_FILE_TYPE, - TEST_FILE_SIZE, - "PARSE_FAILED", - TEST_UPLOAD_TIME); - DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( - "FAILED", "Parse failed", failedResponse); - when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) - .thenReturn(ResponseEntity.ok(response)); - } - - private void mockPollingTimeout() { - DashScopeApi.QueryFileResponseData processingResponse = new DashScopeApi.QueryFileResponseData( - TEST_CATEGORY_ID, - TEST_FILE_ID, - TEST_FILE_NAME, - TEST_FILE_TYPE, - TEST_FILE_SIZE, - "PROCESSING", - TEST_UPLOAD_TIME); - DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( - "SUCCESS", "Processing", processingResponse); - when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) - .thenReturn(ResponseEntity.ok(response)); - } + private static final String TEST_CATEGORY_ID = "test-category"; + + private static final String TEST_FILE_ID = "test-file-id"; + + private static final String TEST_CONTENT = "Test content"; + + private static final String TEST_FILE_NAME = "test.txt"; + + private static final String TEST_FILE_TYPE = "txt"; + + private static final long TEST_FILE_SIZE = 1024L; + + private static final String TEST_UPLOAD_TIME = "2024-01-01 00:00:00"; + + @Mock + private DashScopeApi dashScopeApi; + + @TempDir + Path tempDir; + + private DashScopeDocumentCloudReader reader; + + private File testFile; + + @BeforeEach + void setUp() throws IOException { + // Initialize mocks and test objects + MockitoAnnotations.openMocks(this); + + // Create test file + testFile = tempDir.resolve(TEST_FILE_NAME).toFile(); + Files.writeString(testFile.toPath(), TEST_CONTENT); + + // Set up reader with options + DashScopeDocumentCloudReaderOptions options = new DashScopeDocumentCloudReaderOptions(TEST_CATEGORY_ID); + reader = new DashScopeDocumentCloudReader(testFile.getAbsolutePath(), dashScopeApi, options); + + // Mock successful file upload + mockSuccessfulUpload(); + } + + @Test + void testConstructorWithNonExistentFile() { + // Test constructor with non-existent file + String nonExistentPath = tempDir.resolve("nonexistent.txt").toString(); + assertThatThrownBy(() -> new DashScopeDocumentCloudReader(nonExistentPath, dashScopeApi, + new DashScopeDocumentCloudReaderOptions())) + .isInstanceOf(RuntimeException.class); + } + + @Test + void testSuccessfulDocumentParsing() throws IOException { + // Test successful document parsing + mockSuccessfulParsing(); + + List documents = reader.get(); + + assertThat(documents).hasSize(1); + assertThat(documents.get(0).getText()).isEqualTo(TEST_CONTENT); + } + + @Test + void testParseFailure() throws IOException { + // Test parse failure + mockFailedParsing(); + + assertThatThrownBy(() -> reader.get()).isInstanceOf(RuntimeException.class); + } + + private void mockSuccessfulUpload() { + DashScopeApi.UploadRequest request = new DashScopeApi.UploadRequest(TEST_CATEGORY_ID, TEST_FILE_NAME, + TEST_FILE_SIZE, "md5"); + when(dashScopeApi.upload(any(File.class), any(DashScopeApi.UploadRequest.class))).thenReturn(TEST_FILE_ID); + } + + private void mockSuccessfulParsing() { + DashScopeApi.QueryFileResponseData successResponse = new DashScopeApi.QueryFileResponseData(TEST_CATEGORY_ID, + TEST_FILE_ID, TEST_FILE_NAME, TEST_FILE_TYPE, TEST_FILE_SIZE, "PARSE_SUCCESS", TEST_UPLOAD_TIME); + DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( + "SUCCESS", "OK", successResponse); + when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) + .thenReturn(ResponseEntity.ok(response)); + when(dashScopeApi.getFileParseResult(eq(TEST_CATEGORY_ID), + any(DashScopeApi.UploadRequest.QueryFileRequest.class))) + .thenReturn(TEST_CONTENT); + } + + private void mockFailedParsing() { + DashScopeApi.QueryFileResponseData failedResponse = new DashScopeApi.QueryFileResponseData(TEST_CATEGORY_ID, + TEST_FILE_ID, TEST_FILE_NAME, TEST_FILE_TYPE, TEST_FILE_SIZE, "PARSE_FAILED", TEST_UPLOAD_TIME); + DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( + "FAILED", "Parse failed", failedResponse); + when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) + .thenReturn(ResponseEntity.ok(response)); + } + + private void mockPollingTimeout() { + DashScopeApi.QueryFileResponseData processingResponse = new DashScopeApi.QueryFileResponseData(TEST_CATEGORY_ID, + TEST_FILE_ID, TEST_FILE_NAME, TEST_FILE_TYPE, TEST_FILE_SIZE, "PROCESSING", TEST_UPLOAD_TIME); + DashScopeApi.CommonResponse response = new DashScopeApi.CommonResponse<>( + "SUCCESS", "Processing", processingResponse); + when(dashScopeApi.queryFileInfo(eq(TEST_CATEGORY_ID), any(DashScopeApi.UploadRequest.QueryFileRequest.class))) + .thenReturn(ResponseEntity.ok(response)); + } + } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java index ede09d06..7c49f9df 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrievalAdvisorTests.java @@ -53,8 +53,8 @@ import static org.mockito.Mockito.when; /** - * Test cases for DashScopeDocumentRetrievalAdvisor. Tests cover document - * retrieval, prompt generation, and error handling scenarios. + * Test cases for DashScopeDocumentRetrievalAdvisor. Tests cover document retrieval, + * prompt generation, and error handling scenarios. * * @author kevinlin09 * @author brianxiadong @@ -62,87 +62,92 @@ */ class DashScopeDocumentRetrievalAdvisorTests { - private static final String TEST_CATEGORY_ID = "test-category"; - private static final String TEST_FILE_ID = "test-file-id"; - private static final String TEST_CONTENT = "Test content"; - private static final String TEST_FILE_NAME = "test.txt"; - private static final String TEST_QUERY = "test query"; + private static final String TEST_CATEGORY_ID = "test-category"; - @Mock - private DocumentRetriever documentRetriever; + private static final String TEST_FILE_ID = "test-file-id"; - @Mock - private ChatModel chatModel; + private static final String TEST_CONTENT = "Test content"; - @TempDir - Path tempDir; + private static final String TEST_FILE_NAME = "test.txt"; - private DashScopeDocumentRetrievalAdvisor advisor; - private File testFile; + private static final String TEST_QUERY = "test query"; - @BeforeEach - void setUp() throws IOException { - // Initialize mocks and test objects - MockitoAnnotations.openMocks(this); + @Mock + private DocumentRetriever documentRetriever; - // Create test file - testFile = tempDir.resolve(TEST_FILE_NAME).toFile(); - Files.writeString(testFile.toPath(), TEST_CONTENT); + @Mock + private ChatModel chatModel; - // Set up advisor with document retriever and enable reference - advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); - } + @TempDir + Path tempDir; - @Test - void testGeneratePromptWithDocuments() { - // Prepare test data - List documents = List.of(new Document(TEST_CONTENT)); - when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); + private DashScopeDocumentRetrievalAdvisor advisor; - // Generate prompt - Map userParams = new HashMap<>(); - Map adviseContext = new HashMap<>(); - AdvisedRequest request = AdvisedRequest.builder() - .userText(TEST_QUERY) - .userParams(userParams) - .adviseContext(adviseContext) - .chatModel(chatModel) - .build(); + private File testFile; - // Create a valid ChatResponse with Generation and metadata - Map metadata = new HashMap<>(); - metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); - AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); - ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() - .finishReason(ChatCompletionFinishReason.STOP.name()) - .build(); - Generation generation = new Generation(assistantMessage, generationMetadata); - ChatResponse chatResponse = new ChatResponse(List.of(generation)); + @BeforeEach + void setUp() throws IOException { + // Initialize mocks and test objects + MockitoAnnotations.openMocks(this); - // Create adviseContext with document map - Map responseAdviseContext = new HashMap<>(); - Map documentMap = new HashMap<>(); - documentMap.put("[1]", documents.get(0)); - responseAdviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + // Create test file + testFile = tempDir.resolve(TEST_FILE_NAME).toFile(); + Files.writeString(testFile.toPath(), TEST_CONTENT); - // Create question_answer_context as a Map - Map qaContext = new HashMap<>(); - qaContext.put("context", String.format("[1] 【文档名】%s\n【标题】%s\n【正文】%s\n\n", - documents.get(0).getMetadata().getOrDefault("doc_name", ""), - documents.get(0).getMetadata().getOrDefault("title", ""), - documents.get(0).getText())); - responseAdviseContext.put("question_answer_context", qaContext); + // Set up advisor with document retriever and enable reference + advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); + } - AdvisedResponse response = advisor.aroundCall(request, - chain -> new AdvisedResponse(chatResponse, responseAdviseContext)); + @Test + void testGeneratePromptWithDocuments() { + // Prepare test data + List documents = List.of(new Document(TEST_CONTENT)); + when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); - // Verify response - assertThat(response).isNotNull(); - assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); - assertThat(response.adviseContext()).containsKey("question_answer_context"); - } + // Generate prompt + Map userParams = new HashMap<>(); + Map adviseContext = new HashMap<>(); + AdvisedRequest request = AdvisedRequest.builder() + .userText(TEST_QUERY) + .userParams(userParams) + .adviseContext(adviseContext) + .chatModel(chatModel) + .build(); + + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Create adviseContext with document map + Map responseAdviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + documentMap.put("[1]", documents.get(0)); + responseAdviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + + // Create question_answer_context as a Map + Map qaContext = new HashMap<>(); + qaContext.put("context", + String.format("[1] 【文档名】%s\n【标题】%s\n【正文】%s\n\n", + documents.get(0).getMetadata().getOrDefault("doc_name", ""), + documents.get(0).getMetadata().getOrDefault("title", ""), documents.get(0).getText())); + responseAdviseContext.put("question_answer_context", qaContext); + + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, responseAdviseContext)); - @Test + // Verify response + assertThat(response).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); + assertThat(response.adviseContext()).containsKey("question_answer_context"); + } + + @Test void testGeneratePromptWithEmptyDocuments() { // Prepare test data when(documentRetriever.retrieve(any(Query.class))).thenReturn(Collections.emptyList()); @@ -182,156 +187,143 @@ void testGeneratePromptWithEmptyDocuments() { .isEmpty(); } - @Test - void testProcessChatResponse() { - // Prepare test data - List documents = List.of(new Document(TEST_CONTENT)); - when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); - - // Create chat response with metadata - Map metadata = new HashMap<>(); - metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); - AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); - ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() - .finishReason(ChatCompletionFinishReason.STOP.name()) - .build(); - Generation generation = new Generation(assistantMessage, generationMetadata); - ChatResponse chatResponse = new ChatResponse(List.of(generation)); - - // Process response - Map userParams = new HashMap<>(); - Map adviseContext = new HashMap<>(); - AdvisedRequest request = AdvisedRequest.builder() - .userText(TEST_QUERY) - .userParams(userParams) - .adviseContext(adviseContext) - .chatModel(chatModel) - .build(); - AdvisedResponse response = advisor.aroundCall(request, - chain -> new AdvisedResponse(chatResponse, new HashMap<>())); - - // Verify response - assertThat(response).isNotNull(); - assertThat(response.response()).isNotNull(); - assertThat(response.response().getResult().getOutput().getText()).isEqualTo("Test response"); - } - - @Test - void testAroundCallWithEmptyDocuments() { - // Given - DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); - AdvisedRequest request = AdvisedRequest - .builder() - .userText("test message") - .chatModel(chatModel) - .build(); - - // When - when(documentRetriever.retrieve(any(Query.class))).thenReturn(Collections.emptyList()); - - // Create a valid ChatResponse with Generation and metadata - Map metadata = new HashMap<>(); - metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); - AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); - ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() - .finishReason(ChatCompletionFinishReason.STOP.name()) - .build(); - Generation generation = new Generation(assistantMessage, generationMetadata); - ChatResponse chatResponse = new ChatResponse(List.of(generation)); - - // Create adviseContext with retrieved documents - Map adviseContext = new HashMap<>(); - Map documentMap = new HashMap<>(); - adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); - - AdvisedResponse response = advisor.aroundCall(request, - chain -> new AdvisedResponse(chatResponse, adviseContext)); - - // Then - assertThat(response).isNotNull(); - assertThat(response.response()).isNotNull(); - assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); - } - - @Test - void testAroundCallWithNullDocuments() { - // Given - DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); - AdvisedRequest request = AdvisedRequest - .builder() - .userText("test message") - .chatModel(chatModel) - .build(); - - // When - when(documentRetriever.retrieve(any(Query.class))).thenReturn(Collections.emptyList()); - - // Create a valid ChatResponse with Generation and metadata - Map metadata = new HashMap<>(); - metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); - AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); - ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() - .finishReason(ChatCompletionFinishReason.STOP.name()) - .build(); - Generation generation = new Generation(assistantMessage, generationMetadata); - ChatResponse chatResponse = new ChatResponse(List.of(generation)); - - // Create adviseContext with retrieved documents - Map adviseContext = new HashMap<>(); - Map documentMap = new HashMap<>(); - adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); - - AdvisedResponse response = advisor.aroundCall(request, - chain -> new AdvisedResponse(chatResponse, adviseContext)); - - // Then - assertThat(response).isNotNull(); - assertThat(response.response()).isNotNull(); - assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); - assertThat((Map) response.adviseContext().get(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS)) - .isEmpty(); - } - - @Test - void testAroundCallWithDocuments() { - // Given - DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); - AdvisedRequest request = AdvisedRequest - .builder() - .userText("test message") - .chatModel(chatModel) - .build(); - - // When - List documents = Arrays.asList( - new Document("test document 1"), - new Document("test document 2")); - when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); - - // Create a valid ChatResponse with Generation and metadata - Map metadata = new HashMap<>(); - metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); - AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); - ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() - .finishReason(ChatCompletionFinishReason.STOP.name()) - .build(); - Generation generation = new Generation(assistantMessage, generationMetadata); - ChatResponse chatResponse = new ChatResponse(List.of(generation)); - - // Create adviseContext with retrieved documents - Map adviseContext = new HashMap<>(); - Map documentMap = new HashMap<>(); - for (int i = 0; i < documents.size(); i++) { - documentMap.put(String.format("[%d]", i + 1), documents.get(i)); - } - adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); - - AdvisedResponse response = advisor.aroundCall(request, - chain -> new AdvisedResponse(chatResponse, adviseContext)); + @Test + void testProcessChatResponse() { + // Prepare test data + List documents = List.of(new Document(TEST_CONTENT)); + when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); + + // Create chat response with metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Process response + Map userParams = new HashMap<>(); + Map adviseContext = new HashMap<>(); + AdvisedRequest request = AdvisedRequest.builder() + .userText(TEST_QUERY) + .userParams(userParams) + .adviseContext(adviseContext) + .chatModel(chatModel) + .build(); + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, new HashMap<>())); + + // Verify response + assertThat(response).isNotNull(); + assertThat(response.response()).isNotNull(); + assertThat(response.response().getResult().getOutput().getText()).isEqualTo("Test response"); + } + + @Test + void testAroundCallWithEmptyDocuments() { + // Given + DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); + AdvisedRequest request = AdvisedRequest.builder().userText("test message").chatModel(chatModel).build(); + + // When + when(documentRetriever.retrieve(any(Query.class))).thenReturn(Collections.emptyList()); + + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Create adviseContext with retrieved documents + Map adviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, adviseContext)); + + // Then + assertThat(response).isNotNull(); + assertThat(response.response()).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); + } + + @Test + void testAroundCallWithNullDocuments() { + // Given + DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); + AdvisedRequest request = AdvisedRequest.builder().userText("test message").chatModel(chatModel).build(); + + // When + when(documentRetriever.retrieve(any(Query.class))).thenReturn(Collections.emptyList()); + + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Create adviseContext with retrieved documents + Map adviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, adviseContext)); + + // Then + assertThat(response).isNotNull(); + assertThat(response.response()).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); + assertThat((Map) response.adviseContext().get(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS)) + .isEmpty(); + } + + @Test + void testAroundCallWithDocuments() { + // Given + DashScopeDocumentRetrievalAdvisor advisor = new DashScopeDocumentRetrievalAdvisor(documentRetriever, true); + AdvisedRequest request = AdvisedRequest.builder().userText("test message").chatModel(chatModel).build(); + + // When + List documents = Arrays.asList(new Document("test document 1"), new Document("test document 2")); + when(documentRetriever.retrieve(any(Query.class))).thenReturn(documents); + + // Create a valid ChatResponse with Generation and metadata + Map metadata = new HashMap<>(); + metadata.put("finishReason", ChatCompletionFinishReason.STOP.name()); + AssistantMessage assistantMessage = new AssistantMessage("Test response", metadata); + ChatGenerationMetadata generationMetadata = ChatGenerationMetadata.builder() + .finishReason(ChatCompletionFinishReason.STOP.name()) + .build(); + Generation generation = new Generation(assistantMessage, generationMetadata); + ChatResponse chatResponse = new ChatResponse(List.of(generation)); + + // Create adviseContext with retrieved documents + Map adviseContext = new HashMap<>(); + Map documentMap = new HashMap<>(); + for (int i = 0; i < documents.size(); i++) { + documentMap.put(String.format("[%d]", i + 1), documents.get(i)); + } + adviseContext.put(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS, documentMap); + + AdvisedResponse response = advisor.aroundCall(request, + chain -> new AdvisedResponse(chatResponse, adviseContext)); + + // Then + assertThat(response).isNotNull(); + assertThat(response.response()).isNotNull(); + assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); + } - // Then - assertThat(response).isNotNull(); - assertThat(response.response()).isNotNull(); - assertThat(response.adviseContext()).containsKey(DashScopeDocumentRetrievalAdvisor.RETRIEVED_DOCUMENTS); - } } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverOptionsTests.java index 891d0901..93580b60 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverOptionsTests.java @@ -19,8 +19,8 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test cases for DashScopeDocumentRetrieverOptions. - * Tests cover builder pattern, getters/setters, and default values. + * Test cases for DashScopeDocumentRetrieverOptions. Tests cover builder pattern, + * getters/setters, and default values. * * @author yuluo * @author yuluo @@ -29,106 +29,113 @@ */ class DashScopeDocumentRetrieverOptionsTests { - // Test constants - private static final String TEST_INDEX_NAME = "test-index"; - private static final int TEST_DENSE_TOP_K = 50; - private static final int TEST_SPARSE_TOP_K = 30; - private static final String TEST_REWRITE_MODEL = "test-rewrite-model"; - private static final String TEST_RERANK_MODEL = "test-rerank-model"; - private static final float TEST_RERANK_MIN_SCORE = 0.5f; - private static final int TEST_RERANK_TOP_N = 10; - - @Test - void testDefaultValues() { - // Test default constructor and default values - DashScopeDocumentRetrieverOptions options = new DashScopeDocumentRetrieverOptions(); - - // Verify default values - assertThat(options.getIndexName()).isNull(); - assertThat(options.getDenseSimilarityTopK()).isEqualTo(100); - assertThat(options.getSparseSimilarityTopK()).isEqualTo(100); - assertThat(options.isEnableRewrite()).isFalse(); - assertThat(options.getRewriteModelName()).isEqualTo("conv-rewrite-qwen-1.8b"); - assertThat(options.isEnableReranking()).isTrue(); - assertThat(options.getRerankModelName()).isEqualTo("gte-rerank-hybrid"); - assertThat(options.getRerankMinScore()).isEqualTo(0.01f); - assertThat(options.getRerankTopN()).isEqualTo(5); - } - - @Test - void testBuilderPattern() { - // Test builder pattern with all properties set - DashScopeDocumentRetrieverOptions options = DashScopeDocumentRetrieverOptions.builder() - .withIndexName(TEST_INDEX_NAME) - .withDenseSimilarityTopK(TEST_DENSE_TOP_K) - .withSparseSimilarityTopK(TEST_SPARSE_TOP_K) - .withEnableRewrite(true) - .withRewriteModelName(TEST_REWRITE_MODEL) - .withEnableReranking(false) - .withRerankModelName(TEST_RERANK_MODEL) - .withRerankMinScore(TEST_RERANK_MIN_SCORE) - .withRerankTopN(TEST_RERANK_TOP_N) - .build(); - - // Verify all properties are set correctly - assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); - assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); - assertThat(options.getSparseSimilarityTopK()).isEqualTo(TEST_SPARSE_TOP_K); - assertThat(options.isEnableRewrite()).isTrue(); - assertThat(options.getRewriteModelName()).isEqualTo(TEST_REWRITE_MODEL); - assertThat(options.isEnableReranking()).isFalse(); - assertThat(options.getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); - assertThat(options.getRerankMinScore()).isEqualTo(TEST_RERANK_MIN_SCORE); - assertThat(options.getRerankTopN()).isEqualTo(TEST_RERANK_TOP_N); - } - - @Test - void testSettersAndGetters() { - // Test setters and getters - DashScopeDocumentRetrieverOptions options = new DashScopeDocumentRetrieverOptions(); - - // Set values using setters - options.setIndexName(TEST_INDEX_NAME); - options.setDenseSimilarityTopk(TEST_DENSE_TOP_K); - options.setSparseSimilarityTopk(TEST_SPARSE_TOP_K); - options.setEnableRewrite(true); - options.setRewriteModelName(TEST_REWRITE_MODEL); - options.setEnableReranking(false); - options.setRerankModelName(TEST_RERANK_MODEL); - options.setRerankMinScore(TEST_RERANK_MIN_SCORE); - options.setRerankTopN(TEST_RERANK_TOP_N); - - // Verify values using getters - assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); - assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); - assertThat(options.getSparseSimilarityTopK()).isEqualTo(TEST_SPARSE_TOP_K); - assertThat(options.isEnableRewrite()).isTrue(); - assertThat(options.getRewriteModelName()).isEqualTo(TEST_REWRITE_MODEL); - assertThat(options.isEnableReranking()).isFalse(); - assertThat(options.getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); - assertThat(options.getRerankMinScore()).isEqualTo(TEST_RERANK_MIN_SCORE); - assertThat(options.getRerankTopN()).isEqualTo(TEST_RERANK_TOP_N); - } - - @Test - void testBuilderWithPartialValues() { - // Test builder with only some properties set - DashScopeDocumentRetrieverOptions options = DashScopeDocumentRetrieverOptions.builder() - .withIndexName(TEST_INDEX_NAME) - .withDenseSimilarityTopK(TEST_DENSE_TOP_K) - .build(); - - // Verify set values - assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); - assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); - - // Verify unset values remain at defaults - assertThat(options.getSparseSimilarityTopK()).isEqualTo(100); - assertThat(options.isEnableRewrite()).isFalse(); - assertThat(options.getRewriteModelName()).isEqualTo("conv-rewrite-qwen-1.8b"); - assertThat(options.isEnableReranking()).isTrue(); - assertThat(options.getRerankModelName()).isEqualTo("gte-rerank-hybrid"); - assertThat(options.getRerankMinScore()).isEqualTo(0.01f); - assertThat(options.getRerankTopN()).isEqualTo(5); - } + // Test constants + private static final String TEST_INDEX_NAME = "test-index"; + + private static final int TEST_DENSE_TOP_K = 50; + + private static final int TEST_SPARSE_TOP_K = 30; + + private static final String TEST_REWRITE_MODEL = "test-rewrite-model"; + + private static final String TEST_RERANK_MODEL = "test-rerank-model"; + + private static final float TEST_RERANK_MIN_SCORE = 0.5f; + + private static final int TEST_RERANK_TOP_N = 10; + + @Test + void testDefaultValues() { + // Test default constructor and default values + DashScopeDocumentRetrieverOptions options = new DashScopeDocumentRetrieverOptions(); + + // Verify default values + assertThat(options.getIndexName()).isNull(); + assertThat(options.getDenseSimilarityTopK()).isEqualTo(100); + assertThat(options.getSparseSimilarityTopK()).isEqualTo(100); + assertThat(options.isEnableRewrite()).isFalse(); + assertThat(options.getRewriteModelName()).isEqualTo("conv-rewrite-qwen-1.8b"); + assertThat(options.isEnableReranking()).isTrue(); + assertThat(options.getRerankModelName()).isEqualTo("gte-rerank-hybrid"); + assertThat(options.getRerankMinScore()).isEqualTo(0.01f); + assertThat(options.getRerankTopN()).isEqualTo(5); + } + + @Test + void testBuilderPattern() { + // Test builder pattern with all properties set + DashScopeDocumentRetrieverOptions options = DashScopeDocumentRetrieverOptions.builder() + .withIndexName(TEST_INDEX_NAME) + .withDenseSimilarityTopK(TEST_DENSE_TOP_K) + .withSparseSimilarityTopK(TEST_SPARSE_TOP_K) + .withEnableRewrite(true) + .withRewriteModelName(TEST_REWRITE_MODEL) + .withEnableReranking(false) + .withRerankModelName(TEST_RERANK_MODEL) + .withRerankMinScore(TEST_RERANK_MIN_SCORE) + .withRerankTopN(TEST_RERANK_TOP_N) + .build(); + + // Verify all properties are set correctly + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); + assertThat(options.getSparseSimilarityTopK()).isEqualTo(TEST_SPARSE_TOP_K); + assertThat(options.isEnableRewrite()).isTrue(); + assertThat(options.getRewriteModelName()).isEqualTo(TEST_REWRITE_MODEL); + assertThat(options.isEnableReranking()).isFalse(); + assertThat(options.getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); + assertThat(options.getRerankMinScore()).isEqualTo(TEST_RERANK_MIN_SCORE); + assertThat(options.getRerankTopN()).isEqualTo(TEST_RERANK_TOP_N); + } + + @Test + void testSettersAndGetters() { + // Test setters and getters + DashScopeDocumentRetrieverOptions options = new DashScopeDocumentRetrieverOptions(); + + // Set values using setters + options.setIndexName(TEST_INDEX_NAME); + options.setDenseSimilarityTopk(TEST_DENSE_TOP_K); + options.setSparseSimilarityTopk(TEST_SPARSE_TOP_K); + options.setEnableRewrite(true); + options.setRewriteModelName(TEST_REWRITE_MODEL); + options.setEnableReranking(false); + options.setRerankModelName(TEST_RERANK_MODEL); + options.setRerankMinScore(TEST_RERANK_MIN_SCORE); + options.setRerankTopN(TEST_RERANK_TOP_N); + + // Verify values using getters + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); + assertThat(options.getSparseSimilarityTopK()).isEqualTo(TEST_SPARSE_TOP_K); + assertThat(options.isEnableRewrite()).isTrue(); + assertThat(options.getRewriteModelName()).isEqualTo(TEST_REWRITE_MODEL); + assertThat(options.isEnableReranking()).isFalse(); + assertThat(options.getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); + assertThat(options.getRerankMinScore()).isEqualTo(TEST_RERANK_MIN_SCORE); + assertThat(options.getRerankTopN()).isEqualTo(TEST_RERANK_TOP_N); + } + + @Test + void testBuilderWithPartialValues() { + // Test builder with only some properties set + DashScopeDocumentRetrieverOptions options = DashScopeDocumentRetrieverOptions.builder() + .withIndexName(TEST_INDEX_NAME) + .withDenseSimilarityTopK(TEST_DENSE_TOP_K) + .build(); + + // Verify set values + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + assertThat(options.getDenseSimilarityTopK()).isEqualTo(TEST_DENSE_TOP_K); + + // Verify unset values remain at defaults + assertThat(options.getSparseSimilarityTopK()).isEqualTo(100); + assertThat(options.isEnableRewrite()).isFalse(); + assertThat(options.getRewriteModelName()).isEqualTo("conv-rewrite-qwen-1.8b"); + assertThat(options.isEnableReranking()).isTrue(); + assertThat(options.getRerankModelName()).isEqualTo("gte-rerank-hybrid"); + assertThat(options.getRerankMinScore()).isEqualTo(0.01f); + assertThat(options.getRerankTopN()).isEqualTo(5); + } + } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverTests.java index e47fa525..66bd831b 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentRetrieverTests.java @@ -37,8 +37,8 @@ import static org.mockito.Mockito.when; /** - * Test cases for DashScopeDocumentRetriever. - * Tests cover document retrieval functionality, error handling, and edge cases. + * Test cases for DashScopeDocumentRetriever. Tests cover document retrieval + * functionality, error handling, and edge cases. * * @author yuluo * @author yuluo @@ -48,48 +48,51 @@ @ExtendWith(MockitoExtension.class) class DashScopeDocumentRetrieverTests { - // Test constants - private static final String TEST_INDEX_NAME = "test-index"; - private static final String TEST_PIPELINE_ID = "test-pipeline-id"; - private static final String TEST_QUERY = "test query"; - private static final String TEST_DOC_ID = "test-doc-id"; - private static final String TEST_DOC_TEXT = "test document text"; + // Test constants + private static final String TEST_INDEX_NAME = "test-index"; - @Mock - private DashScopeApi dashScopeApi; + private static final String TEST_PIPELINE_ID = "test-pipeline-id"; - private DashScopeDocumentRetriever retriever; - private DashScopeDocumentRetrieverOptions options; + private static final String TEST_QUERY = "test query"; - @BeforeEach - void setUp() { - // Initialize options with test values - options = DashScopeDocumentRetrieverOptions.builder() - .withIndexName(TEST_INDEX_NAME) - .build(); + private static final String TEST_DOC_ID = "test-doc-id"; - // Create retriever instance - retriever = new DashScopeDocumentRetriever(dashScopeApi, options); - } + private static final String TEST_DOC_TEXT = "test document text"; - @Test - void testConstructorWithNullOptions() { - // Test constructor with null options - assertThatThrownBy(() -> new DashScopeDocumentRetriever(dashScopeApi, null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("RetrieverOptions must not be null"); - } + @Mock + private DashScopeApi dashScopeApi; - @Test - void testConstructorWithNullIndexName() { - // Test constructor with null index name - DashScopeDocumentRetrieverOptions optionsWithNullIndex = new DashScopeDocumentRetrieverOptions(); - assertThatThrownBy(() -> new DashScopeDocumentRetriever(dashScopeApi, optionsWithNullIndex)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("IndexName must not be null"); - } + private DashScopeDocumentRetriever retriever; + + private DashScopeDocumentRetrieverOptions options; + + @BeforeEach + void setUp() { + // Initialize options with test values + options = DashScopeDocumentRetrieverOptions.builder().withIndexName(TEST_INDEX_NAME).build(); + + // Create retriever instance + retriever = new DashScopeDocumentRetriever(dashScopeApi, options); + } - @Test + @Test + void testConstructorWithNullOptions() { + // Test constructor with null options + assertThatThrownBy(() -> new DashScopeDocumentRetriever(dashScopeApi, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("RetrieverOptions must not be null"); + } + + @Test + void testConstructorWithNullIndexName() { + // Test constructor with null index name + DashScopeDocumentRetrieverOptions optionsWithNullIndex = new DashScopeDocumentRetrieverOptions(); + assertThatThrownBy(() -> new DashScopeDocumentRetriever(dashScopeApi, optionsWithNullIndex)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("IndexName must not be null"); + } + + @Test void testRetrieveWithNonExistentIndex() { // Mock API response for non-existent index when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(null); @@ -100,34 +103,33 @@ void testRetrieveWithNonExistentIndex() { .hasMessageContaining("Index:" + TEST_INDEX_NAME + " NotExist"); } - @Test - void testSuccessfulRetrieval() { - // Create test document with metadata - Map metadata = new HashMap<>(); - metadata.put("doc_name", "test.txt"); - metadata.put("title", "Test Document"); - Document testDoc = new Document(TEST_DOC_ID, TEST_DOC_TEXT, metadata); - List expectedDocs = List.of(testDoc); - - // Mock API responses - when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); - when(dashScopeApi.retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any(DashScopeDocumentRetrieverOptions.class))) - .thenReturn(expectedDocs); - - // Test successful document retrieval - List retrievedDocs = retriever.retrieve(new Query(TEST_QUERY)); - - // Verify retrieved documents - assertThat(retrievedDocs).isNotNull().hasSize(1); - Document retrievedDoc = retrievedDocs.get(0); - assertThat(retrievedDoc.getId()).isEqualTo(TEST_DOC_ID); - assertThat(retrievedDoc.getText()).isEqualTo(TEST_DOC_TEXT); - assertThat(retrievedDoc.getMetadata()) - .containsEntry("doc_name", "test.txt") - .containsEntry("title", "Test Document"); - } - - @Test + @Test + void testSuccessfulRetrieval() { + // Create test document with metadata + Map metadata = new HashMap<>(); + metadata.put("doc_name", "test.txt"); + metadata.put("title", "Test Document"); + Document testDoc = new Document(TEST_DOC_ID, TEST_DOC_TEXT, metadata); + List expectedDocs = List.of(testDoc); + + // Mock API responses + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); + when(dashScopeApi.retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any(DashScopeDocumentRetrieverOptions.class))) + .thenReturn(expectedDocs); + + // Test successful document retrieval + List retrievedDocs = retriever.retrieve(new Query(TEST_QUERY)); + + // Verify retrieved documents + assertThat(retrievedDocs).isNotNull().hasSize(1); + Document retrievedDoc = retrievedDocs.get(0); + assertThat(retrievedDoc.getId()).isEqualTo(TEST_DOC_ID); + assertThat(retrievedDoc.getText()).isEqualTo(TEST_DOC_TEXT); + assertThat(retrievedDoc.getMetadata()).containsEntry("doc_name", "test.txt") + .containsEntry("title", "Test Document"); + } + + @Test void testEmptyRetrieval() { // Mock API responses for empty result when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); @@ -141,35 +143,35 @@ void testEmptyRetrieval() { assertThat(retrievedDocs).isNotNull().isEmpty(); } - @Test - void testRetrievalWithMultipleDocuments() { - // Create multiple test documents - List expectedDocs = new ArrayList<>(); - for (int i = 0; i < 3; i++) { - Map metadata = new HashMap<>(); - metadata.put("doc_name", "test" + i + ".txt"); - metadata.put("title", "Test Document " + i); - Document doc = new Document("doc-" + i, "content " + i, metadata); - expectedDocs.add(doc); - } - - // Mock API responses - when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); - when(dashScopeApi.retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any(DashScopeDocumentRetrieverOptions.class))) - .thenReturn(expectedDocs); + @Test + void testRetrievalWithMultipleDocuments() { + // Create multiple test documents + List expectedDocs = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Map metadata = new HashMap<>(); + metadata.put("doc_name", "test" + i + ".txt"); + metadata.put("title", "Test Document " + i); + Document doc = new Document("doc-" + i, "content " + i, metadata); + expectedDocs.add(doc); + } + + // Mock API responses + when(dashScopeApi.getPipelineIdByName(TEST_INDEX_NAME)).thenReturn(TEST_PIPELINE_ID); + when(dashScopeApi.retriever(eq(TEST_PIPELINE_ID), eq(TEST_QUERY), any(DashScopeDocumentRetrieverOptions.class))) + .thenReturn(expectedDocs); + + // Test retrieval with multiple documents + List retrievedDocs = retriever.retrieve(new Query(TEST_QUERY)); + + // Verify retrieved documents + assertThat(retrievedDocs).isNotNull().hasSize(3); + for (int i = 0; i < retrievedDocs.size(); i++) { + Document doc = retrievedDocs.get(i); + assertThat(doc.getId()).isEqualTo("doc-" + i); + assertThat(doc.getText()).isEqualTo("content " + i); + assertThat(doc.getMetadata()).containsEntry("doc_name", "test" + i + ".txt") + .containsEntry("title", "Test Document " + i); + } + } - // Test retrieval with multiple documents - List retrievedDocs = retriever.retrieve(new Query(TEST_QUERY)); - - // Verify retrieved documents - assertThat(retrievedDocs).isNotNull().hasSize(3); - for (int i = 0; i < retrievedDocs.size(); i++) { - Document doc = retrievedDocs.get(i); - assertThat(doc.getId()).isEqualTo("doc-" + i); - assertThat(doc.getText()).isEqualTo("content " + i); - assertThat(doc.getMetadata()) - .containsEntry("doc_name", "test" + i + ".txt") - .containsEntry("title", "Test Document " + i); - } - } } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerOptionsTests.java index cb80bb5d..3bc3a35e 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerOptionsTests.java @@ -19,9 +19,8 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test cases for DashScopeDocumentTransformerOptions. - * Tests cover default values, builder pattern, setters/getters, and partial - * value settings. + * Test cases for DashScopeDocumentTransformerOptions. Tests cover default values, builder + * pattern, setters/getters, and partial value settings. * * @author yuluo * @author yuluo @@ -30,94 +29,97 @@ */ class DashScopeDocumentTransformerOptionsTests { - // Test constants for validation - private static final int TEST_CHUNK_SIZE = 1000; - private static final int TEST_OVERLAP_SIZE = 200; - private static final String TEST_SEPARATOR = "|,|,|。|?|!|\\n"; - private static final String TEST_FILE_TYPE = "txt"; - private static final String TEST_LANGUAGE = "en"; - - /** - * Test default values when creating a new instance. - * Verifies that all properties have their expected default values. - */ - @Test - void testDefaultValues() { - DashScopeDocumentTransformerOptions options = new DashScopeDocumentTransformerOptions(); - - // Verify default values - assertThat(options.getChunkSize()).isEqualTo(500); - assertThat(options.getOverlapSize()).isEqualTo(100); - assertThat(options.getSeparator()).isEqualTo("|,|,|。|?|!|\\n|\\\\?|\\\\!"); - assertThat(options.getFileType()).isEqualTo("idp"); - assertThat(options.getLanguage()).isEqualTo("cn"); - } - - /** - * Test the builder pattern for setting all properties. - * Verifies that all properties can be set using the builder pattern. - */ - @Test - void testBuilderPattern() { - DashScopeDocumentTransformerOptions options = DashScopeDocumentTransformerOptions.builder() - .withChunkSize(TEST_CHUNK_SIZE) - .withOverlapSize(TEST_OVERLAP_SIZE) - .withSeparator(TEST_SEPARATOR) - .withFileType(TEST_FILE_TYPE) - .withLanguage(TEST_LANGUAGE) - .build(); - - // Verify all properties are set correctly - assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); - assertThat(options.getOverlapSize()).isEqualTo(TEST_OVERLAP_SIZE); - assertThat(options.getSeparator()).isEqualTo(TEST_SEPARATOR); - assertThat(options.getFileType()).isEqualTo(TEST_FILE_TYPE); - assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); - } - - /** - * Test all setter and getter methods. - * Verifies that all properties can be set and retrieved correctly using setters - * and getters. - */ - @Test - void testSettersAndGetters() { - DashScopeDocumentTransformerOptions options = new DashScopeDocumentTransformerOptions(); - - // Set values using setters - options.setChunkSize(TEST_CHUNK_SIZE); - options.setOverlapSize(TEST_OVERLAP_SIZE); - options.setSeparator(TEST_SEPARATOR); - options.setFileType(TEST_FILE_TYPE); - options.setLanguage(TEST_LANGUAGE); - - // Verify values using getters - assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); - assertThat(options.getOverlapSize()).isEqualTo(TEST_OVERLAP_SIZE); - assertThat(options.getSeparator()).isEqualTo(TEST_SEPARATOR); - assertThat(options.getFileType()).isEqualTo(TEST_FILE_TYPE); - assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); - } - - /** - * Test builder with partial values set. - * Verifies that when only some properties are set, others retain their default - * values. - */ - @Test - void testBuilderWithPartialValues() { - DashScopeDocumentTransformerOptions options = DashScopeDocumentTransformerOptions.builder() - .withChunkSize(TEST_CHUNK_SIZE) - .withLanguage(TEST_LANGUAGE) - .build(); - - // Verify set values - assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); - assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); - - // Verify default values for unset properties - assertThat(options.getOverlapSize()).isEqualTo(100); - assertThat(options.getSeparator()).isEqualTo("|,|,|。|?|!|\\n|\\\\?|\\\\!"); - assertThat(options.getFileType()).isEqualTo("idp"); - } + // Test constants for validation + private static final int TEST_CHUNK_SIZE = 1000; + + private static final int TEST_OVERLAP_SIZE = 200; + + private static final String TEST_SEPARATOR = "|,|,|。|?|!|\\n"; + + private static final String TEST_FILE_TYPE = "txt"; + + private static final String TEST_LANGUAGE = "en"; + + /** + * Test default values when creating a new instance. Verifies that all properties have + * their expected default values. + */ + @Test + void testDefaultValues() { + DashScopeDocumentTransformerOptions options = new DashScopeDocumentTransformerOptions(); + + // Verify default values + assertThat(options.getChunkSize()).isEqualTo(500); + assertThat(options.getOverlapSize()).isEqualTo(100); + assertThat(options.getSeparator()).isEqualTo("|,|,|。|?|!|\\n|\\\\?|\\\\!"); + assertThat(options.getFileType()).isEqualTo("idp"); + assertThat(options.getLanguage()).isEqualTo("cn"); + } + + /** + * Test the builder pattern for setting all properties. Verifies that all properties + * can be set using the builder pattern. + */ + @Test + void testBuilderPattern() { + DashScopeDocumentTransformerOptions options = DashScopeDocumentTransformerOptions.builder() + .withChunkSize(TEST_CHUNK_SIZE) + .withOverlapSize(TEST_OVERLAP_SIZE) + .withSeparator(TEST_SEPARATOR) + .withFileType(TEST_FILE_TYPE) + .withLanguage(TEST_LANGUAGE) + .build(); + + // Verify all properties are set correctly + assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); + assertThat(options.getOverlapSize()).isEqualTo(TEST_OVERLAP_SIZE); + assertThat(options.getSeparator()).isEqualTo(TEST_SEPARATOR); + assertThat(options.getFileType()).isEqualTo(TEST_FILE_TYPE); + assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); + } + + /** + * Test all setter and getter methods. Verifies that all properties can be set and + * retrieved correctly using setters and getters. + */ + @Test + void testSettersAndGetters() { + DashScopeDocumentTransformerOptions options = new DashScopeDocumentTransformerOptions(); + + // Set values using setters + options.setChunkSize(TEST_CHUNK_SIZE); + options.setOverlapSize(TEST_OVERLAP_SIZE); + options.setSeparator(TEST_SEPARATOR); + options.setFileType(TEST_FILE_TYPE); + options.setLanguage(TEST_LANGUAGE); + + // Verify values using getters + assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); + assertThat(options.getOverlapSize()).isEqualTo(TEST_OVERLAP_SIZE); + assertThat(options.getSeparator()).isEqualTo(TEST_SEPARATOR); + assertThat(options.getFileType()).isEqualTo(TEST_FILE_TYPE); + assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); + } + + /** + * Test builder with partial values set. Verifies that when only some properties are + * set, others retain their default values. + */ + @Test + void testBuilderWithPartialValues() { + DashScopeDocumentTransformerOptions options = DashScopeDocumentTransformerOptions.builder() + .withChunkSize(TEST_CHUNK_SIZE) + .withLanguage(TEST_LANGUAGE) + .build(); + + // Verify set values + assertThat(options.getChunkSize()).isEqualTo(TEST_CHUNK_SIZE); + assertThat(options.getLanguage()).isEqualTo(TEST_LANGUAGE); + + // Verify default values for unset properties + assertThat(options.getOverlapSize()).isEqualTo(100); + assertThat(options.getSeparator()).isEqualTo("|,|,|。|?|!|\\n|\\\\?|\\\\!"); + assertThat(options.getFileType()).isEqualTo("idp"); + } + } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerTests.java index 6cdbde09..d53ec817 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeDocumentTransformerTests.java @@ -36,9 +36,8 @@ import static org.mockito.Mockito.when; /** - * Test cases for DashScopeDocumentTransformer. - * Tests cover constructor validation, document splitting, error handling, and - * successful transformations. + * Test cases for DashScopeDocumentTransformer. Tests cover constructor validation, + * document splitting, error handling, and successful transformations. * * @author yuluo * @author yuluo @@ -47,161 +46,151 @@ */ class DashScopeDocumentTransformerTests { - // Test constants - private static final String TEST_DOC_ID = "test_doc_1"; - private static final String TEST_CONTENT = "This is a test document content"; - private static final String TEST_CHUNK_CONTENT = "This is a test chunk content"; - private static final int TEST_CHUNK_ID = 1; - - @Mock - private DashScopeApi dashScopeApi; - - private DashScopeDocumentTransformer transformer; - private DashScopeDocumentTransformerOptions options; - - @BeforeEach - void setUp() { - // Initialize mocks - MockitoAnnotations.openMocks(this); - - // Create default options - options = DashScopeDocumentTransformerOptions.builder() - .withChunkSize(500) - .withOverlapSize(100) - .withSeparator("|,|,|。|?|!|\\n|\\\\?|\\\\!") - .withFileType("idp") - .withLanguage("cn") - .build(); - - // Create transformer instance - transformer = new DashScopeDocumentTransformer(dashScopeApi, options); - } - - /** - * Test constructor with null DashScopeApi. - * Should throw IllegalArgumentException. - */ - @Test - void testConstructorWithNullApi() { - assertThatThrownBy(() -> new DashScopeDocumentTransformer(null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("DashScopeApi must not be null"); - } - - /** - * Test constructor with null options. - * Should throw IllegalArgumentException. - */ - @Test - void testConstructorWithNullOptions() { - assertThatThrownBy(() -> new DashScopeDocumentTransformer(dashScopeApi, null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("DashScopeDocumentTransformerOptions must not be null"); - } - - /** - * Test applying transformation with null documents list. - * Should throw RuntimeException. - */ - @Test - void testApplyWithNullDocuments() { - assertThatThrownBy(() -> transformer.apply(null)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("Documents must not be null"); - } - - /** - * Test applying transformation with empty documents list. - * Should throw RuntimeException. - */ - @Test - void testApplyWithEmptyDocuments() { - assertThatThrownBy(() -> transformer.apply(Collections.emptyList())) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("Documents must not be null"); - } - - /** - * Test applying transformation with multiple documents. - * Should throw RuntimeException as only one document is supported. - */ - @Test - void testApplyWithMultipleDocuments() { - Map metadata = new HashMap<>(); - List documents = List.of( - new Document(TEST_DOC_ID, TEST_CONTENT, metadata), - new Document("test_doc_2", "Another test content", metadata)); - - assertThatThrownBy(() -> transformer.apply(documents)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("Just support one Document"); - } - - /** - * Test successful document splitting. - * Should return list of document chunks with correct IDs and content. - */ - @Test - void testSuccessfulSplit() { - // Create test document - Map metadata = new HashMap<>(); - Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); - - // Mock API response - DashScopeApi.DocumentSplitResponse.DocumentChunk chunk = new DashScopeApi.DocumentSplitResponse.DocumentChunk( - TEST_CHUNK_ID, TEST_CHUNK_CONTENT, null, null, null, null); - DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData chunkService = new DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData( - List.of(chunk)); - DashScopeApi.DocumentSplitResponse response = new DashScopeApi.DocumentSplitResponse(chunkService); - - when(dashScopeApi.documentSplit(any(), any())) - .thenReturn(ResponseEntity.ok(response)); - - // Perform transformation - List result = transformer.apply(List.of(document)); - - // Verify results - assertThat(result).isNotNull() - .hasSize(1); - Document resultDoc = result.get(0); - assertThat(resultDoc.getId()).isEqualTo(TEST_DOC_ID + "_" + TEST_CHUNK_ID); - assertThat(resultDoc.getText()).isEqualTo(TEST_CHUNK_CONTENT); - assertThat(resultDoc.getMetadata()).isEqualTo(metadata); - } - - /** - * Test split with null API response. - * Should throw DashScopeException. - */ - @Test - void testSplitWithNullResponse() { - Map metadata = new HashMap<>(); - Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); - - when(dashScopeApi.documentSplit(any(), any())) - .thenReturn(null); - - assertThatThrownBy(() -> transformer.apply(List.of(document))) - .isInstanceOf(DashScopeException.class); - } - - /** - * Test split with empty chunks in response. - * Should throw DashScopeException. - */ - @Test - void testSplitWithEmptyChunks() { - Map metadata = new HashMap<>(); - Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); - - DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData chunkService = new DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData( - Collections.emptyList()); - DashScopeApi.DocumentSplitResponse response = new DashScopeApi.DocumentSplitResponse(chunkService); - - when(dashScopeApi.documentSplit(any(), any())) - .thenReturn(ResponseEntity.ok(response)); - - assertThatThrownBy(() -> transformer.apply(List.of(document))) - .isInstanceOf(DashScopeException.class); - } + // Test constants + private static final String TEST_DOC_ID = "test_doc_1"; + + private static final String TEST_CONTENT = "This is a test document content"; + + private static final String TEST_CHUNK_CONTENT = "This is a test chunk content"; + + private static final int TEST_CHUNK_ID = 1; + + @Mock + private DashScopeApi dashScopeApi; + + private DashScopeDocumentTransformer transformer; + + private DashScopeDocumentTransformerOptions options; + + @BeforeEach + void setUp() { + // Initialize mocks + MockitoAnnotations.openMocks(this); + + // Create default options + options = DashScopeDocumentTransformerOptions.builder() + .withChunkSize(500) + .withOverlapSize(100) + .withSeparator("|,|,|。|?|!|\\n|\\\\?|\\\\!") + .withFileType("idp") + .withLanguage("cn") + .build(); + + // Create transformer instance + transformer = new DashScopeDocumentTransformer(dashScopeApi, options); + } + + /** + * Test constructor with null DashScopeApi. Should throw IllegalArgumentException. + */ + @Test + void testConstructorWithNullApi() { + assertThatThrownBy(() -> new DashScopeDocumentTransformer(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("DashScopeApi must not be null"); + } + + /** + * Test constructor with null options. Should throw IllegalArgumentException. + */ + @Test + void testConstructorWithNullOptions() { + assertThatThrownBy(() -> new DashScopeDocumentTransformer(dashScopeApi, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("DashScopeDocumentTransformerOptions must not be null"); + } + + /** + * Test applying transformation with null documents list. Should throw + * RuntimeException. + */ + @Test + void testApplyWithNullDocuments() { + assertThatThrownBy(() -> transformer.apply(null)).isInstanceOf(RuntimeException.class) + .hasMessageContaining("Documents must not be null"); + } + + /** + * Test applying transformation with empty documents list. Should throw + * RuntimeException. + */ + @Test + void testApplyWithEmptyDocuments() { + assertThatThrownBy(() -> transformer.apply(Collections.emptyList())).isInstanceOf(RuntimeException.class) + .hasMessageContaining("Documents must not be null"); + } + + /** + * Test applying transformation with multiple documents. Should throw RuntimeException + * as only one document is supported. + */ + @Test + void testApplyWithMultipleDocuments() { + Map metadata = new HashMap<>(); + List documents = List.of(new Document(TEST_DOC_ID, TEST_CONTENT, metadata), + new Document("test_doc_2", "Another test content", metadata)); + + assertThatThrownBy(() -> transformer.apply(documents)).isInstanceOf(RuntimeException.class) + .hasMessageContaining("Just support one Document"); + } + + /** + * Test successful document splitting. Should return list of document chunks with + * correct IDs and content. + */ + @Test + void testSuccessfulSplit() { + // Create test document + Map metadata = new HashMap<>(); + Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); + + // Mock API response + DashScopeApi.DocumentSplitResponse.DocumentChunk chunk = new DashScopeApi.DocumentSplitResponse.DocumentChunk( + TEST_CHUNK_ID, TEST_CHUNK_CONTENT, null, null, null, null); + DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData chunkService = new DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData( + List.of(chunk)); + DashScopeApi.DocumentSplitResponse response = new DashScopeApi.DocumentSplitResponse(chunkService); + + when(dashScopeApi.documentSplit(any(), any())).thenReturn(ResponseEntity.ok(response)); + + // Perform transformation + List result = transformer.apply(List.of(document)); + + // Verify results + assertThat(result).isNotNull().hasSize(1); + Document resultDoc = result.get(0); + assertThat(resultDoc.getId()).isEqualTo(TEST_DOC_ID + "_" + TEST_CHUNK_ID); + assertThat(resultDoc.getText()).isEqualTo(TEST_CHUNK_CONTENT); + assertThat(resultDoc.getMetadata()).isEqualTo(metadata); + } + + /** + * Test split with null API response. Should throw DashScopeException. + */ + @Test + void testSplitWithNullResponse() { + Map metadata = new HashMap<>(); + Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); + + when(dashScopeApi.documentSplit(any(), any())).thenReturn(null); + + assertThatThrownBy(() -> transformer.apply(List.of(document))).isInstanceOf(DashScopeException.class); + } + + /** + * Test split with empty chunks in response. Should throw DashScopeException. + */ + @Test + void testSplitWithEmptyChunks() { + Map metadata = new HashMap<>(); + Document document = new Document(TEST_DOC_ID, TEST_CONTENT, metadata); + + DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData chunkService = new DashScopeApi.DocumentSplitResponse.DocumentSplitResponseData( + Collections.emptyList()); + DashScopeApi.DocumentSplitResponse response = new DashScopeApi.DocumentSplitResponse(chunkService); + + when(dashScopeApi.documentSplit(any(), any())).thenReturn(ResponseEntity.ok(response)); + + assertThatThrownBy(() -> transformer.apply(List.of(document))).isInstanceOf(DashScopeException.class); + } + } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeStoreOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeStoreOptionsTests.java index d7dc7bf8..bb6b911a 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeStoreOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rag/DashScopeStoreOptionsTests.java @@ -21,8 +21,8 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test cases for DashScopeStoreOptions. - * Tests cover constructor, getters/setters, and option configurations. + * Test cases for DashScopeStoreOptions. Tests cover constructor, getters/setters, and + * option configurations. * * @author yuluo * @author yuluo @@ -31,132 +31,135 @@ */ class DashScopeStoreOptionsTests { - // Test constants for validation - private static final String TEST_INDEX_NAME = "test-index"; - private static final String TEST_EMBEDDING_MODEL = "text-embedding-v2"; - private static final String TEST_RERANK_MODEL = "gte-rerank-hybrid"; - - /** - * Test constructor with index name. - * Verifies that the index name is correctly set in the constructor. - */ - @Test - void testConstructorWithIndexName() { - DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); - - // Verify index name is set correctly - assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); - - // Verify other options are null by default - assertThat(options.getTransformerOptions()).isNull(); - assertThat(options.getEmbeddingOptions()).isNull(); - assertThat(options.getRetrieverOptions()).isNull(); - } - - /** - * Test setters and getters for all options. - * Verifies that all options can be set and retrieved correctly. - */ - @Test - void testSettersAndGetters() { - DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); - - // Create and set transformer options - DashScopeDocumentTransformerOptions transformerOptions = new DashScopeDocumentTransformerOptions(); - transformerOptions.setChunkSize(1000); - options.setTransformerOptions(transformerOptions); - - // Create and set embedding options - DashScopeEmbeddingOptions embeddingOptions = DashScopeEmbeddingOptions.builder() - .withModel(TEST_EMBEDDING_MODEL) - .build(); - options.setEmbeddingOptions(embeddingOptions); - - // Create and set retriever options - DashScopeDocumentRetrieverOptions retrieverOptions = DashScopeDocumentRetrieverOptions.builder() - .withRerankModelName(TEST_RERANK_MODEL) - .build(); - options.setRetrieverOptions(retrieverOptions); - - // Verify all options are set correctly - assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); - assertThat(options.getTransformerOptions()).isEqualTo(transformerOptions); - assertThat(options.getEmbeddingOptions()).isEqualTo(embeddingOptions); - assertThat(options.getRetrieverOptions()).isEqualTo(retrieverOptions); - } - - /** - * Test setting index name after construction. - * Verifies that the index name can be modified after object creation. - */ - @Test - void testSetIndexName() { - String newIndexName = "new-test-index"; - DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); - - options.setIndexName(newIndexName); - - assertThat(options.getIndexName()).isEqualTo(newIndexName); - } - - /** - * Test setting transformer options with default values. - * Verifies that transformer options with default values are handled correctly. - */ - @Test - void testTransformerOptionsWithDefaults() { - DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); - DashScopeDocumentTransformerOptions transformerOptions = new DashScopeDocumentTransformerOptions(); - - options.setTransformerOptions(transformerOptions); - - // Verify default values - assertThat(options.getTransformerOptions().getChunkSize()).isEqualTo(500); - assertThat(options.getTransformerOptions().getOverlapSize()).isEqualTo(100); - assertThat(options.getTransformerOptions().getLanguage()).isEqualTo("cn"); - } - - /** - * Test setting embedding options with custom configuration. - * Verifies that embedding options can be customized and retrieved correctly. - */ - @Test - void testEmbeddingOptionsWithCustomConfig() { - DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); - DashScopeEmbeddingOptions embeddingOptions = DashScopeEmbeddingOptions.builder() - .withModel(TEST_EMBEDDING_MODEL) - .withTextType("document") - .withDimensions(1536) - .build(); - - options.setEmbeddingOptions(embeddingOptions); - - // Verify custom values - assertThat(options.getEmbeddingOptions().getModel()).isEqualTo(TEST_EMBEDDING_MODEL); - assertThat(options.getEmbeddingOptions().getTextType()).isEqualTo("document"); - assertThat(options.getEmbeddingOptions().getDimensions()).isEqualTo(1536); - } - - /** - * Test setting retriever options with custom configuration. - * Verifies that retriever options can be customized and retrieved correctly. - */ - @Test - void testRetrieverOptionsWithCustomConfig() { - DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); - DashScopeDocumentRetrieverOptions retrieverOptions = DashScopeDocumentRetrieverOptions.builder() - .withDenseSimilarityTopK(50) - .withSparseSimilarityTopK(30) - .withEnableReranking(true) - .withRerankModelName(TEST_RERANK_MODEL) - .build(); - - options.setRetrieverOptions(retrieverOptions); - - // Verify custom values - assertThat(options.getRetrieverOptions().getDenseSimilarityTopK()).isEqualTo(50); - assertThat(options.getRetrieverOptions().getSparseSimilarityTopK()).isEqualTo(30); - assertThat(options.getRetrieverOptions().isEnableReranking()).isTrue(); - assertThat(options.getRetrieverOptions().getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); - } + // Test constants for validation + private static final String TEST_INDEX_NAME = "test-index"; + + private static final String TEST_EMBEDDING_MODEL = "text-embedding-v2"; + + private static final String TEST_RERANK_MODEL = "gte-rerank-hybrid"; + + /** + * Test constructor with index name. Verifies that the index name is correctly set in + * the constructor. + */ + @Test + void testConstructorWithIndexName() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + + // Verify index name is set correctly + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + + // Verify other options are null by default + assertThat(options.getTransformerOptions()).isNull(); + assertThat(options.getEmbeddingOptions()).isNull(); + assertThat(options.getRetrieverOptions()).isNull(); + } + + /** + * Test setters and getters for all options. Verifies that all options can be set and + * retrieved correctly. + */ + @Test + void testSettersAndGetters() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + + // Create and set transformer options + DashScopeDocumentTransformerOptions transformerOptions = new DashScopeDocumentTransformerOptions(); + transformerOptions.setChunkSize(1000); + options.setTransformerOptions(transformerOptions); + + // Create and set embedding options + DashScopeEmbeddingOptions embeddingOptions = DashScopeEmbeddingOptions.builder() + .withModel(TEST_EMBEDDING_MODEL) + .build(); + options.setEmbeddingOptions(embeddingOptions); + + // Create and set retriever options + DashScopeDocumentRetrieverOptions retrieverOptions = DashScopeDocumentRetrieverOptions.builder() + .withRerankModelName(TEST_RERANK_MODEL) + .build(); + options.setRetrieverOptions(retrieverOptions); + + // Verify all options are set correctly + assertThat(options.getIndexName()).isEqualTo(TEST_INDEX_NAME); + assertThat(options.getTransformerOptions()).isEqualTo(transformerOptions); + assertThat(options.getEmbeddingOptions()).isEqualTo(embeddingOptions); + assertThat(options.getRetrieverOptions()).isEqualTo(retrieverOptions); + } + + /** + * Test setting index name after construction. Verifies that the index name can be + * modified after object creation. + */ + @Test + void testSetIndexName() { + String newIndexName = "new-test-index"; + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + + options.setIndexName(newIndexName); + + assertThat(options.getIndexName()).isEqualTo(newIndexName); + } + + /** + * Test setting transformer options with default values. Verifies that transformer + * options with default values are handled correctly. + */ + @Test + void testTransformerOptionsWithDefaults() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + DashScopeDocumentTransformerOptions transformerOptions = new DashScopeDocumentTransformerOptions(); + + options.setTransformerOptions(transformerOptions); + + // Verify default values + assertThat(options.getTransformerOptions().getChunkSize()).isEqualTo(500); + assertThat(options.getTransformerOptions().getOverlapSize()).isEqualTo(100); + assertThat(options.getTransformerOptions().getLanguage()).isEqualTo("cn"); + } + + /** + * Test setting embedding options with custom configuration. Verifies that embedding + * options can be customized and retrieved correctly. + */ + @Test + void testEmbeddingOptionsWithCustomConfig() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + DashScopeEmbeddingOptions embeddingOptions = DashScopeEmbeddingOptions.builder() + .withModel(TEST_EMBEDDING_MODEL) + .withTextType("document") + .withDimensions(1536) + .build(); + + options.setEmbeddingOptions(embeddingOptions); + + // Verify custom values + assertThat(options.getEmbeddingOptions().getModel()).isEqualTo(TEST_EMBEDDING_MODEL); + assertThat(options.getEmbeddingOptions().getTextType()).isEqualTo("document"); + assertThat(options.getEmbeddingOptions().getDimensions()).isEqualTo(1536); + } + + /** + * Test setting retriever options with custom configuration. Verifies that retriever + * options can be customized and retrieved correctly. + */ + @Test + void testRetrieverOptionsWithCustomConfig() { + DashScopeStoreOptions options = new DashScopeStoreOptions(TEST_INDEX_NAME); + DashScopeDocumentRetrieverOptions retrieverOptions = DashScopeDocumentRetrieverOptions.builder() + .withDenseSimilarityTopK(50) + .withSparseSimilarityTopK(30) + .withEnableReranking(true) + .withRerankModelName(TEST_RERANK_MODEL) + .build(); + + options.setRetrieverOptions(retrieverOptions); + + // Verify custom values + assertThat(options.getRetrieverOptions().getDenseSimilarityTopK()).isEqualTo(50); + assertThat(options.getRetrieverOptions().getSparseSimilarityTopK()).isEqualTo(30); + assertThat(options.getRetrieverOptions().isEnableReranking()).isTrue(); + assertThat(options.getRetrieverOptions().getRerankModelName()).isEqualTo(TEST_RERANK_MODEL); + } + } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankModelTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankModelTests.java index 2a6fa25f..ebf8b37f 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankModelTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankModelTests.java @@ -41,9 +41,8 @@ import static org.mockito.Mockito.when; /** - * Test cases for DashScopeRerankModel. - * Tests cover constructor validation, reranking functionality, error handling, - * and response processing. + * Test cases for DashScopeRerankModel. Tests cover constructor validation, reranking + * functionality, error handling, and response processing. * * @author yuanci.ytb * @author yuluo @@ -53,167 +52,166 @@ @ExtendWith(MockitoExtension.class) class DashScopeRerankModelTests { - // Test constants - private static final String TEST_MODEL = "gte-rerank"; - private static final String TEST_QUERY = "test query"; - private static final String TEST_DOC_TEXT = "test document text"; - private static final Double TEST_SCORE = 0.85; - - @Mock - private DashScopeApi dashScopeApi; - - private DashScopeRerankModel rerankModel; - private DashScopeRerankOptions defaultOptions; - - @BeforeEach - void setUp() { - // Initialize default options - defaultOptions = DashScopeRerankOptions.builder() - .withModel(TEST_MODEL) - .withTopN(3) - .withReturnDocuments(false) - .build(); - - // Initialize rerank model - rerankModel = new DashScopeRerankModel(dashScopeApi, defaultOptions); - } - - /** - * Test constructor with null DashScopeApi. - * Verifies that constructor throws IllegalArgumentException when DashScopeApi - * is null. - */ - @Test - void testConstructorWithNullApi() { - assertThatThrownBy(() -> new DashScopeRerankModel(null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("DashScopeApi must not be null"); - } - - /** - * Test constructor with null options. - * Verifies that constructor throws IllegalArgumentException when options is - * null. - */ - @Test - void testConstructorWithNullOptions() { - assertThatThrownBy(() -> new DashScopeRerankModel(dashScopeApi, null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Options must not be null"); - } - - /** - * Test reranking with null query. - * Verifies that reranking throws IllegalArgumentException when query is null. - */ - @Test - void testRerankWithNullQuery() { - List documents = Collections.singletonList(new Document(TEST_DOC_TEXT)); - RerankRequest request = new RerankRequest(null, documents); - - assertThatThrownBy(() -> rerankModel.call(request)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("query must not be null"); - } - - /** - * Test reranking with null documents. - * Verifies that reranking throws IllegalArgumentException when documents list - * is null. - */ - @Test - void testRerankWithNullDocuments() { - RerankRequest request = new RerankRequest(TEST_QUERY, null); - - assertThatThrownBy(() -> rerankModel.call(request)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("documents must not be null"); - } - - /** - * Test successful reranking. - * Verifies that reranking returns correct scores and documents. - */ - @Test - void testSuccessfulRerank() { - // Prepare test data - Document doc1 = new Document(TEST_DOC_TEXT + "1"); - Document doc2 = new Document(TEST_DOC_TEXT + "2"); - List documents = Arrays.asList(doc1, doc2); - - // Mock API response - RerankResponseOutputResult result1 = new RerankResponseOutputResult(0, 0.9, new HashMap<>()); - RerankResponseOutputResult result2 = new RerankResponseOutputResult(1, 0.7, new HashMap<>()); - RerankResponseOutput output = new RerankResponseOutput(Arrays.asList(result1, result2)); - TokenUsage usage = new TokenUsage(10, 20, 30); - RerankResponse apiResponse = new RerankResponse(output, usage, "test-request-id"); - - when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(apiResponse)); - - // Execute rerank - RerankRequest request = new RerankRequest(TEST_QUERY, documents); - com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); - - // Verify results - List results = response.getResults(); - assertThat(results).hasSize(2); - assertThat(results.get(0).getScore()).isEqualTo(0.9); - assertThat(results.get(1).getScore()).isEqualTo(0.7); - assertThat(results.get(0).getOutput()).isEqualTo(doc1); - assertThat(results.get(1).getOutput()).isEqualTo(doc2); - } - - /** - * Test reranking with empty response. - * Verifies that reranking handles empty API response correctly. - */ - @Test - void testEmptyResponse() { - // Prepare test data - Document doc = new Document(TEST_DOC_TEXT); - List documents = Collections.singletonList(doc); - - // Mock empty API response - when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(null)); - - // Execute rerank - RerankRequest request = new RerankRequest(TEST_QUERY, documents); - com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); - - // Verify empty results - assertThat(response.getResults()).isEmpty(); - } - - /** - * Test reranking with custom options. - * Verifies that reranking uses custom options correctly. - */ - @Test - void testCustomOptions() { - // Prepare test data - Document doc = new Document(TEST_DOC_TEXT); - List documents = Collections.singletonList(doc); - - // Create custom options - DashScopeRerankOptions customOptions = DashScopeRerankOptions.builder() - .withModel("custom-model") - .withTopN(5) - .withReturnDocuments(true) - .build(); - - // Mock API response - RerankResponseOutputResult result = new RerankResponseOutputResult(0, TEST_SCORE, new HashMap<>()); - RerankResponseOutput output = new RerankResponseOutput(Collections.singletonList(result)); - RerankResponse apiResponse = new RerankResponse(output, new TokenUsage(10, 20, 30), "test-request-id"); - - when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(apiResponse)); - - // Execute rerank with custom options - RerankRequest request = new RerankRequest(TEST_QUERY, documents, customOptions); - com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); - - // Verify results - assertThat(response.getResults()).hasSize(1); - assertThat(response.getResults().get(0).getScore()).isEqualTo(TEST_SCORE); - } + // Test constants + private static final String TEST_MODEL = "gte-rerank"; + + private static final String TEST_QUERY = "test query"; + + private static final String TEST_DOC_TEXT = "test document text"; + + private static final Double TEST_SCORE = 0.85; + + @Mock + private DashScopeApi dashScopeApi; + + private DashScopeRerankModel rerankModel; + + private DashScopeRerankOptions defaultOptions; + + @BeforeEach + void setUp() { + // Initialize default options + defaultOptions = DashScopeRerankOptions.builder() + .withModel(TEST_MODEL) + .withTopN(3) + .withReturnDocuments(false) + .build(); + + // Initialize rerank model + rerankModel = new DashScopeRerankModel(dashScopeApi, defaultOptions); + } + + /** + * Test constructor with null DashScopeApi. Verifies that constructor throws + * IllegalArgumentException when DashScopeApi is null. + */ + @Test + void testConstructorWithNullApi() { + assertThatThrownBy(() -> new DashScopeRerankModel(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("DashScopeApi must not be null"); + } + + /** + * Test constructor with null options. Verifies that constructor throws + * IllegalArgumentException when options is null. + */ + @Test + void testConstructorWithNullOptions() { + assertThatThrownBy(() -> new DashScopeRerankModel(dashScopeApi, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Options must not be null"); + } + + /** + * Test reranking with null query. Verifies that reranking throws + * IllegalArgumentException when query is null. + */ + @Test + void testRerankWithNullQuery() { + List documents = Collections.singletonList(new Document(TEST_DOC_TEXT)); + RerankRequest request = new RerankRequest(null, documents); + + assertThatThrownBy(() -> rerankModel.call(request)).isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("query must not be null"); + } + + /** + * Test reranking with null documents. Verifies that reranking throws + * IllegalArgumentException when documents list is null. + */ + @Test + void testRerankWithNullDocuments() { + RerankRequest request = new RerankRequest(TEST_QUERY, null); + + assertThatThrownBy(() -> rerankModel.call(request)).isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("documents must not be null"); + } + + /** + * Test successful reranking. Verifies that reranking returns correct scores and + * documents. + */ + @Test + void testSuccessfulRerank() { + // Prepare test data + Document doc1 = new Document(TEST_DOC_TEXT + "1"); + Document doc2 = new Document(TEST_DOC_TEXT + "2"); + List documents = Arrays.asList(doc1, doc2); + + // Mock API response + RerankResponseOutputResult result1 = new RerankResponseOutputResult(0, 0.9, new HashMap<>()); + RerankResponseOutputResult result2 = new RerankResponseOutputResult(1, 0.7, new HashMap<>()); + RerankResponseOutput output = new RerankResponseOutput(Arrays.asList(result1, result2)); + TokenUsage usage = new TokenUsage(10, 20, 30); + RerankResponse apiResponse = new RerankResponse(output, usage, "test-request-id"); + + when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(apiResponse)); + + // Execute rerank + RerankRequest request = new RerankRequest(TEST_QUERY, documents); + com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); + + // Verify results + List results = response.getResults(); + assertThat(results).hasSize(2); + assertThat(results.get(0).getScore()).isEqualTo(0.9); + assertThat(results.get(1).getScore()).isEqualTo(0.7); + assertThat(results.get(0).getOutput()).isEqualTo(doc1); + assertThat(results.get(1).getOutput()).isEqualTo(doc2); + } + + /** + * Test reranking with empty response. Verifies that reranking handles empty API + * response correctly. + */ + @Test + void testEmptyResponse() { + // Prepare test data + Document doc = new Document(TEST_DOC_TEXT); + List documents = Collections.singletonList(doc); + + // Mock empty API response + when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(null)); + + // Execute rerank + RerankRequest request = new RerankRequest(TEST_QUERY, documents); + com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); + + // Verify empty results + assertThat(response.getResults()).isEmpty(); + } + + /** + * Test reranking with custom options. Verifies that reranking uses custom options + * correctly. + */ + @Test + void testCustomOptions() { + // Prepare test data + Document doc = new Document(TEST_DOC_TEXT); + List documents = Collections.singletonList(doc); + + // Create custom options + DashScopeRerankOptions customOptions = DashScopeRerankOptions.builder() + .withModel("custom-model") + .withTopN(5) + .withReturnDocuments(true) + .build(); + + // Mock API response + RerankResponseOutputResult result = new RerankResponseOutputResult(0, TEST_SCORE, new HashMap<>()); + RerankResponseOutput output = new RerankResponseOutput(Collections.singletonList(result)); + RerankResponse apiResponse = new RerankResponse(output, new TokenUsage(10, 20, 30), "test-request-id"); + + when(dashScopeApi.rerankEntity(any())).thenReturn(ResponseEntity.ok(apiResponse)); + + // Execute rerank with custom options + RerankRequest request = new RerankRequest(TEST_QUERY, documents, customOptions); + com.alibaba.cloud.ai.model.RerankResponse response = rerankModel.call(request); + + // Verify results + assertThat(response.getResults()).hasSize(1); + assertThat(response.getResults().get(0).getScore()).isEqualTo(TEST_SCORE); + } + } diff --git a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankOptionsTests.java b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankOptionsTests.java index af3899f9..137743ff 100644 --- a/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankOptionsTests.java +++ b/spring-ai-alibaba-core/src/test/java/com/alibaba/cloud/ai/dashscope/rerank/DashScopeRerankOptionsTests.java @@ -19,8 +19,8 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test cases for DashScopeRerankOptions. - * Tests cover default values, builder pattern, and property modifications. + * Test cases for DashScopeRerankOptions. Tests cover default values, builder pattern, and + * property modifications. * * @author yuluo * @author yuluo @@ -29,77 +29,75 @@ */ class DashScopeRerankOptionsTests { - // Test constants - private static final String TEST_MODEL = "test-rerank-model"; - private static final Integer TEST_TOP_N = 5; - private static final Boolean TEST_RETURN_DOCUMENTS = true; + // Test constants + private static final String TEST_MODEL = "test-rerank-model"; - /** - * Test default values of DashScopeRerankOptions. - * Verifies that a newly created instance has the expected default values: - * - model = "gte-rerank" - * - topN = 3 - * - returnDocuments = false - */ - @Test - void testDefaultValues() { - DashScopeRerankOptions options = DashScopeRerankOptions.builder().build(); + private static final Integer TEST_TOP_N = 5; - assertThat(options.getModel()).isEqualTo("gte-rerank"); - assertThat(options.getTopN()).isEqualTo(3); - assertThat(options.getReturnDocuments()).isFalse(); - } + private static final Boolean TEST_RETURN_DOCUMENTS = true; - /** - * Test builder pattern with all properties set. - * Verifies that all properties can be set using the builder pattern - * and are correctly assigned to the created instance. - */ - @Test - void testBuilderPattern() { - DashScopeRerankOptions options = DashScopeRerankOptions.builder() - .withModel(TEST_MODEL) - .withTopN(TEST_TOP_N) - .withReturnDocuments(TEST_RETURN_DOCUMENTS) - .build(); + /** + * Test default values of DashScopeRerankOptions. Verifies that a newly created + * instance has the expected default values: - model = "gte-rerank" - topN = 3 - + * returnDocuments = false + */ + @Test + void testDefaultValues() { + DashScopeRerankOptions options = DashScopeRerankOptions.builder().build(); - assertThat(options.getModel()).isEqualTo(TEST_MODEL); - assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); - assertThat(options.getReturnDocuments()).isEqualTo(TEST_RETURN_DOCUMENTS); - } + assertThat(options.getModel()).isEqualTo("gte-rerank"); + assertThat(options.getTopN()).isEqualTo(3); + assertThat(options.getReturnDocuments()).isFalse(); + } - /** - * Test setters and getters. - * Verifies that all properties can be modified after instance creation - * using setter methods and retrieved using getter methods. - */ - @Test - void testSettersAndGetters() { - DashScopeRerankOptions options = DashScopeRerankOptions.builder().build(); + /** + * Test builder pattern with all properties set. Verifies that all properties can be + * set using the builder pattern and are correctly assigned to the created instance. + */ + @Test + void testBuilderPattern() { + DashScopeRerankOptions options = DashScopeRerankOptions.builder() + .withModel(TEST_MODEL) + .withTopN(TEST_TOP_N) + .withReturnDocuments(TEST_RETURN_DOCUMENTS) + .build(); - options.setModel(TEST_MODEL); - options.setTopN(TEST_TOP_N); - options.setReturnDocuments(TEST_RETURN_DOCUMENTS); + assertThat(options.getModel()).isEqualTo(TEST_MODEL); + assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); + assertThat(options.getReturnDocuments()).isEqualTo(TEST_RETURN_DOCUMENTS); + } - assertThat(options.getModel()).isEqualTo(TEST_MODEL); - assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); - assertThat(options.getReturnDocuments()).isEqualTo(TEST_RETURN_DOCUMENTS); - } + /** + * Test setters and getters. Verifies that all properties can be modified after + * instance creation using setter methods and retrieved using getter methods. + */ + @Test + void testSettersAndGetters() { + DashScopeRerankOptions options = DashScopeRerankOptions.builder().build(); - /** - * Test builder with partial values set. - * Verifies that when only some properties are set using the builder, - * the unset properties retain their default values. - */ - @Test - void testBuilderWithPartialValues() { - DashScopeRerankOptions options = DashScopeRerankOptions.builder() - .withModel(TEST_MODEL) - .withTopN(TEST_TOP_N) - .build(); + options.setModel(TEST_MODEL); + options.setTopN(TEST_TOP_N); + options.setReturnDocuments(TEST_RETURN_DOCUMENTS); + + assertThat(options.getModel()).isEqualTo(TEST_MODEL); + assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); + assertThat(options.getReturnDocuments()).isEqualTo(TEST_RETURN_DOCUMENTS); + } + + /** + * Test builder with partial values set. Verifies that when only some properties are + * set using the builder, the unset properties retain their default values. + */ + @Test + void testBuilderWithPartialValues() { + DashScopeRerankOptions options = DashScopeRerankOptions.builder() + .withModel(TEST_MODEL) + .withTopN(TEST_TOP_N) + .build(); + + assertThat(options.getModel()).isEqualTo(TEST_MODEL); + assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); + assertThat(options.getReturnDocuments()).isFalse(); // Default value + } - assertThat(options.getModel()).isEqualTo(TEST_MODEL); - assertThat(options.getTopN()).isEqualTo(TEST_TOP_N); - assertThat(options.getReturnDocuments()).isFalse(); // Default value - } }