feat(rag-store): 补充知识库文档概览接口

This commit is contained in:
zhiye.sun
2026-05-21 15:35:45 +08:00
parent 541c3ff455
commit 8532628171
11 changed files with 484 additions and 17 deletions

View File

@@ -10,6 +10,8 @@ import com.bruce.rag.controller.RagStoreController;
import com.bruce.rag.dto.request.RagDocumentQueryRequest;
import com.bruce.rag.dto.request.RagStoreQueryRequest;
import com.bruce.rag.dto.request.RagStoreSaveRequest;
import com.bruce.rag.dto.response.RagStoreDocumentOverviewResponse;
import com.bruce.rag.dto.response.RagStoreOverviewResponse;
import com.bruce.rag.dto.response.RagDocumentResponse;
import com.bruce.rag.dto.response.RagStoreResponse;
import com.bruce.rag.entity.RagDocument;
@@ -21,12 +23,14 @@ import com.bruce.rag.service.IRagStoreService;
import com.bruce.rag.service.impl.RagDocumentServiceImpl;
import com.bruce.rag.service.impl.RagStoreServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.web.bind.annotation.PostMapping;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class RagComponentStructureTests {
@@ -46,11 +50,15 @@ class RagComponentStructureTests {
Method storeListMethod = RagStoreController.class.getMethod("list");
Method storeQueryMethod = RagStoreController.class.getMethod("query", RagStoreQueryRequest.class);
Method storeDetailMethod = RagStoreController.class.getMethod("getById", Long.class);
Method storeOverviewMethod = RagStoreController.class.getMethod("overview");
Method storeDocumentOverviewMethod = RagStoreController.class.getMethod("documentOverview", Long.class);
Method storeSaveMethod = RagStoreController.class.getMethod("saveOrUpdate", RagStoreSaveRequest.class);
Method storeDeleteMethod = RagStoreController.class.getMethod("deleteById", Long.class);
Method storeResponseListMethod = IRagStoreService.class.getMethod("listResponses");
Method storeServiceQueryMethod = IRagStoreService.class.getMethod("query", RagStoreQueryRequest.class);
Method storeServiceDetailMethod = IRagStoreService.class.getMethod("getResponseById", Long.class);
Method storeServiceOverviewMethod = IRagStoreService.class.getMethod("getOverview");
Method storeServiceDocumentOverviewMethod = IRagStoreService.class.getMethod("getDocumentOverview", Long.class);
Method storeServiceSaveMethod = IRagStoreService.class.getMethod("saveOrUpdate", RagStoreSaveRequest.class);
Method documentListMethod = RagDocumentController.class.getMethod("list");
@@ -61,16 +69,22 @@ class RagComponentStructureTests {
assertEquals(RequestResult.class, storeListMethod.getReturnType());
assertEquals(RequestResult.class, storeQueryMethod.getReturnType());
assertEquals(RequestResult.class, storeDetailMethod.getReturnType());
assertEquals(RequestResult.class, storeOverviewMethod.getReturnType());
assertEquals(RequestResult.class, storeDocumentOverviewMethod.getReturnType());
assertEquals(RequestResult.class, storeSaveMethod.getReturnType());
assertEquals(RequestResult.class, storeDeleteMethod.getReturnType());
assertEquals(List.class, storeServiceQueryMethod.getReturnType());
assertEquals(RagStoreResponse.class, storeServiceDetailMethod.getReturnType());
assertEquals(RagStoreOverviewResponse.class, storeServiceOverviewMethod.getReturnType());
assertEquals(RagStoreDocumentOverviewResponse.class, storeServiceDocumentOverviewMethod.getReturnType());
assertEquals(boolean.class, storeServiceSaveMethod.getReturnType());
assertTrue(storeResponseListMethod.getGenericReturnType().getTypeName().contains("RagStoreResponse"));
assertTrue(storeServiceQueryMethod.getGenericReturnType().getTypeName().contains("RagStoreResponse"));
assertTrue(storeListMethod.getGenericReturnType().getTypeName().contains("RagStoreResponse"));
assertTrue(storeQueryMethod.getGenericReturnType().getTypeName().contains("RagStoreResponse"));
assertTrue(storeDetailMethod.getGenericReturnType().getTypeName().contains("RagStoreResponse"));
assertTrue(storeOverviewMethod.getGenericReturnType().getTypeName().contains("RagStoreOverviewResponse"));
assertTrue(storeDocumentOverviewMethod.getGenericReturnType().getTypeName().contains("RagStoreDocumentOverviewResponse"));
assertEquals(RagStoreResponse.class, RagStoreResponse.class.getMethod("fromEntity", RagStore.class).getReturnType());
assertEquals(RequestResult.class, documentListMethod.getReturnType());
@@ -83,6 +97,16 @@ class RagComponentStructureTests {
assertEquals(RagDocumentResponse.class, RagDocumentResponse.class.getMethod("fromEntity", RagDocument.class).getReturnType());
}
@Test
void ragDocumentListUrlShouldUseExplicitListAction() throws NoSuchMethodException {
Method documentListMethod = RagDocumentController.class.getMethod("list");
PostMapping postMapping = documentListMethod.getAnnotation(PostMapping.class);
assertNotNull(postMapping);
assertEquals("/list", postMapping.value()[0]);
}
@Test
void ragSourceTypesAndDocumentRelationShouldExist() throws NoSuchFieldException {
Field storeIdField = RagDocument.class.getDeclaredField("storeId");
@@ -90,6 +114,7 @@ class RagComponentStructureTests {
assertEquals("RAG_STORE", RagSystemConstants.RAG_STORE);
assertEquals("RAG_DOCUMENT", RagSystemConstants.RAG_DOCUMENT);
assertEquals("RAG", RagSystemConstants.SOURCE_TYPE_RAG);
assertEquals(Long.class, storeIdField.getType());
assertEquals(Long.class, attachmentIdField.getType());
assertTrue(RagStore.class.getSimpleName().contains("RagStore"));

View File

@@ -0,0 +1,126 @@
package com.bruce.rag;
import com.bruce.common.enums.EnableStatusEnum;
import com.bruce.rag.dto.response.RagDocumentResponse;
import com.bruce.rag.dto.response.RagStoreDocumentOverviewResponse;
import com.bruce.rag.dto.response.RagStoreOverviewResponse;
import com.bruce.rag.entity.RagStore;
import com.bruce.rag.enums.RagIndexStatusEnum;
import com.bruce.rag.enums.RagParseStatusEnum;
import com.bruce.rag.service.IRagDocumentService;
import com.bruce.rag.service.impl.RagStoreServiceImpl;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Date;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class RagStoreOverviewServiceTests {
@Spy
@InjectMocks
private RagStoreServiceImpl ragStoreService;
@Mock
private IRagDocumentService ragDocumentService;
@Test
void getOverviewShouldAggregateStoreAndDocumentCounts() {
RagStore enabledStore = new RagStore();
enabledStore.setId(1L);
enabledStore.setStatus(EnableStatusEnum.ENABLED.getLabel());
RagStore disabledStore = new RagStore();
disabledStore.setId(2L);
disabledStore.setStatus("停用");
when(ragDocumentService.listResponses()).thenReturn(List.of(
createDocumentResponse("11", "1", true, RagParseStatusEnum.UPLOADED.name(), RagIndexStatusEnum.PENDING.name(), new Date()),
createDocumentResponse("22", "2", false, RagParseStatusEnum.PARSED.name(), RagIndexStatusEnum.INDEXED.name(), new Date())
));
doReturn(List.of(enabledStore, disabledStore)).when(ragStoreService).list();
RagStoreOverviewResponse response = ragStoreService.getOverview();
assertEquals(2, response.getTotalStores());
assertEquals(2, response.getTotalDocuments());
assertNull(response.getTotalChunks());
assertEquals(1, response.getRetrievableStores());
}
@Test
void getDocumentOverviewShouldAggregateCurrentStoreDocumentMetrics() {
RagStore store = new RagStore();
store.setId(1L);
store.setStoreName("产品制度库");
doReturn(store).when(ragStoreService).getById(1L);
when(ragDocumentService.query(org.mockito.ArgumentMatchers.any())).thenReturn(List.of(
createDocumentResponse("11", "1", true, RagParseStatusEnum.UPLOADED.name(), RagIndexStatusEnum.PENDING.name(), new Date(1747816496000L)),
createDocumentResponse("12", "1", true, RagParseStatusEnum.PARSED.name(), RagIndexStatusEnum.INDEXED.name(), new Date(1747820096000L)),
createDocumentResponse("13", "1", false, RagParseStatusEnum.FAILED.name(), RagIndexStatusEnum.FAILED.name(), new Date(1747812896000L))
));
RagStoreDocumentOverviewResponse response = ragStoreService.getDocumentOverview(1L);
assertEquals(1L, response.getStoreId());
assertEquals("产品制度库", response.getStoreName());
assertEquals(3, response.getDocumentCount());
assertEquals(2, response.getEnabledDocumentCount());
assertEquals(1, response.getParsedDocumentCount());
assertEquals(1, response.getIndexedDocumentCount());
assertEquals(new Date(1747820096000L), response.getLastUploadTime());
}
@Test
void getDocumentOverviewShouldQueryDocumentsByStoreIdOnly() {
RagStore store = new RagStore();
store.setId(1L);
store.setStoreName("产品制度库");
doReturn(store).when(ragStoreService).getById(1L);
when(ragDocumentService.query(org.mockito.ArgumentMatchers.any())).thenReturn(List.of());
ragStoreService.getDocumentOverview(1L);
org.mockito.ArgumentCaptor<com.bruce.rag.dto.request.RagDocumentQueryRequest> captor =
org.mockito.ArgumentCaptor.forClass(com.bruce.rag.dto.request.RagDocumentQueryRequest.class);
org.mockito.Mockito.verify(ragDocumentService).query(captor.capture());
assertEquals(1L, captor.getValue().getStoreId());
assertNull(captor.getValue().getParseStatus());
assertNull(captor.getValue().getIndexStatus());
}
@Test
void getDocumentOverviewShouldRejectUnknownStore() {
doReturn(null).when(ragStoreService).getById(999L);
assertThrows(IllegalArgumentException.class, () -> ragStoreService.getDocumentOverview(999L));
}
private RagDocumentResponse createDocumentResponse(
String id,
String storeId,
boolean enabled,
String parseStatus,
String indexStatus,
Date createTime
) {
RagDocumentResponse response = new RagDocumentResponse();
response.setId(Long.valueOf(id));
response.setStoreId(Long.valueOf(storeId));
response.setEnabled(enabled);
response.setParseStatus(parseStatus);
response.setIndexStatus(indexStatus);
response.setCreateTime(createTime);
return response;
}
}